HDU - 3341 Lost's revenge(AC自动机+状压dp)
生活随笔
收集整理的這篇文章主要介紹了
HDU - 3341 Lost's revenge(AC自动机+状压dp)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:給出 n 個模式串,最后給出一個匹配串,問如何重新排列匹配串,可以使得匹配串盡可能多的匹配模式串
題目分析:因為是模式串和匹配串的匹配,所以考慮AC自動機,因為數據范圍比較小,且是求最優解,所以考慮dp,因為匹配串的長度最多只有40,而不同的字符只有 4 種,所以可以開個五維dp轉移狀態,dp[ A ][ B ][ C ][ D ][ state ] 表示當四種字符的個數分別選取了 A,B,C,D 個時,狀態為 state 時最多可以匹配的模式串,顯然這樣轉移是正確的,不過問題是這樣開數組會爆內存,但轉念一想,其實并用不了這么多內存,因為 A + B + C +? D 是小于等于 40 的,所以我們可以選擇對其進行哈希壓縮空間,或者直接用進制的思想壓縮,這樣一來只需要開一個二維dp就可以滿足條件了 dp[A,B,C,D][ state ] ,因為最多的種類數是 11*11*11*11,所以數組開這么大就夠了,剩下的直接暴力更新就好了
還有一個小問題,就是需要注意一下上界的問題,不然會WA,添加一些 if 用來限制上界就好了
代碼:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=510;char s[N];int dp[N][11*11*11*11+100],bit[4],num[4];//dp[state][A,B,C,D]int fail[N],cntword[N],trie[N][4],mp[150],cnt;void insert_word() {int len=strlen(s);int pos=0;for(int i=0;i<len;i++){int to=mp[s[i]];if(!trie[pos][to])trie[pos][to]=++cnt;pos=trie[pos][to];}cntword[pos]++; }void getfail() {queue<int>q;for(int i=0;i<4;i++){if(trie[0][i]){fail[trie[0][i]]=0;q.push(trie[0][i]);}}while(!q.empty()){int cur=q.front();q.pop();cntword[cur]+=cntword[fail[cur]];for(int i=0;i<4;i++){if(trie[cur][i]){fail[trie[cur][i]]=trie[fail[cur]][i];q.push(trie[cur][i]);}elsetrie[cur][i]=trie[fail[cur]][i];}} }void init() {cnt=0;memset(cntword,0,sizeof(cntword));memset(trie,0,sizeof(trie));mp['A']=0,mp['C']=1,mp['G']=2,mp['T']=3;memset(dp,-1,sizeof(dp));memset(num,0,sizeof(num));memset(bit,0,sizeof(bit)); }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n;int kase=0;while(scanf("%d",&n)!=EOF&&n){init();while(n--){scanf("%s",s);insert_word();}getfail();scanf("%s",s);int len=strlen(s);for(int i=0;i<len;i++)num[mp[s[i]]]++;bit[0]=1;bit[1]=num[0]+1;bit[2]=(num[0]+1)*(num[1]+1);bit[3]=(num[0]+1)*(num[1]+1)*(num[2]+1);dp[0][0]=0;for(int A=0;A<=num[0];A++)for(int B=0;B<=num[1];B++)for(int C=0;C<=num[2];C++)for(int D=0;D<=num[3];D++){int s=A*bit[0]+B*bit[1]+C*bit[2]+D*bit[3];for(int j=0;j<=cnt;j++)if(dp[j][s]>=0){for(int k=0;k<4;k++){int nj=trie[j][k];if(k==0&&A==num[0])continue;if(k==1&&B==num[1])continue;if(k==2&&C==num[2])continue;if(k==3&&D==num[3])continue;dp[nj][s+bit[k]]=max(dp[nj][s+bit[k]],dp[j][s]+cntword[nj]);}}}int ans=0;int s=bit[0]*num[0]+bit[1]*num[1]+bit[2]*num[2]+bit[3]*num[3];for(int i=0;i<=cnt;i++)ans=max(ans,dp[i][s]);printf("Case %d: %d\n",++kase,ans);}return 0; }?
總結
以上是生活随笔為你收集整理的HDU - 3341 Lost's revenge(AC自动机+状压dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1307D C
- 下一篇: HDU - 3247 Resource