http://acm.hdu.edu.cn/showproblem.php?pid=1560
仔细读题(!),则可发现这道题要求的是一个最短的字符串,该字符串的不连续子序列中包含题目所给的所有字符串
因为总共只有40个字符,可以尝试使用A*搜索
1.存储状态时直接存储40个字符,每个字符4种可能是肯定不行的.
因为要求的是包含不连续的子序列,所以只需记住当前字符串长度与每个子序列已经包含在当前字符串的长度,
比如题目中的输入样例
4
ACGT
ATGC
CGTT
CAGT
可以这样存储一个序列
ATG:len=3,s[0]=1,s[1]=3,s[2]=0,s[3]=0,
ATC:len=3,s[0]=2,a[1]=2,s[2]=1,s[3]=1,
又因为只有8个子序列,每个子序列长度不超过5,也就是说可以采用6进制来压缩状态数组.总共不超过6^9=10077696种状态,空间时间都满足
2.评估函数随便选取了当前未实现的最长长度,2483ms过关
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxsta=10077696; char str[8][6]; int l[8]; int grade[8][6]; bool vis[maxsta]; int s[8]; int n; struct status{ int len,f; int sta; status():len(0),f(0),sta(0){} status(int _len,int _f,int _sta): len(_len),f(_f),sta(_sta){} bool operator <(status s2)const { if(s2.len!=len)return len>s2.len; return f>s2.f; } void tos(){ int tsta=sta; for(int i=n-1;i>=0;i--){ s[i]=sta%6; sta/=6; } sta=tsta; } static int tosta(){ int sta=0; for(int i=0;i<n;i++){ sta*=6; sta+=s[i]; } return sta; } static int calcf(int sta){ int tmp[8]; int ans=0; for(int i=n-1;i>=0;i--){ tmp[i]=sta%6; sta/=6; ans=max(ans,l[i]-tmp[i]); } return ans; } }; priority_queue<status> que; int ed; int bfs(){ while(!que.empty())que.pop(); status st=status(0,status::calcf(0),0); char ch[4]={‘A‘,‘G‘,‘C‘,‘T‘}; que.push(st); vis[0]=true; while(!que.empty()){ status tp=que.top();que.pop(); if(tp.sta==ed)return tp.len; for(int i=0;i<4;i++){ tp.tos(); for(int j=0;j<n;j++){ if(ch[i]==str[j][s[j]]){ s[j]++; } } int tmpsta=status::tosta(); if(vis[tmpsta])continue; vis[tmpsta]=true; if(tmpsta==ed)return tp.len+1; que.push(status(tp.len+1,status::calcf(tmpsta),tmpsta)); } } return -1; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++){ scanf("%s",str[i]); l[i]=strlen(str[i]); s[i]=l[i]; } ed=status::tosta(); int ans=bfs(); printf("%d\n",ans); } return 0; }
时间: 2024-10-07 00:19:38