1. 程式人生 > >[hdu2296]Ring(AC自動機+dp)

[hdu2296]Ring(AC自動機+dp)

stream style ac自動機 sizeof push 字符串 += cnblogs fail

題意:你M個單詞構成一個詞典,每個單詞有一個權值(單詞出現多次算多個權值),現在要你構造一個不超過長度N的字符串,使得該字符串權值最大。如果出現多個答案,輸出最短的,如果依然有多解,輸出字典序最小的。

解題關鍵:最典型的AC自動機上跑dp。

令$dp[i][j] = x$表示走了i步到達j點的最大價值,則

轉移方程:$dp[i][j] = \max (dp[i][j],dp[i-1][k] + val[j])$

$val[i]$代表以某前綴的價值總和。

註意這裏是多對多的關系,需用從遍歷起點時更新後面的點。

  1 #include<cstdio>
  2 #include<cstring>
  3
#include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<queue> 8 #include<string> 9 using namespace std; 10 typedef long long ll; 11 const int N=26; 12 const int MAXN=1101; 13 int m,n; 14 int mod=100000; 15
int val[MAXN]; 16 int dp[52][1101]; 17 string path[52][1101]; 18 struct Trie{ 19 int Next[MAXN][N],Fail[MAXN],root,tot; 20 int End[MAXN]; 21 int newnode(){ 22 for(int i=0;i<N;i++) Next[tot][i]=-1; 23 End[tot++]=0; 24 return tot-1; 25 } 26 void
init(){ 27 tot=0; 28 root=newnode(); 29 } 30 31 void insert(char buf[],int x){ 32 int len=(int)strlen(buf),now=root,k; 33 for(int i=0;i<len;i++){ 34 k=buf[i]-a; 35 if(Next[now][k]==-1) Next[now][k]=newnode(); 36 now=Next[now][k]; 37 } 38 End[now]=x; 39 } 40 41 void build(){ 42 queue<int>que; 43 Fail[root]=root; 44 for(int i=0;i<N;i++){ 45 if(Next[root][i]==-1) Next[root][i]=root; 46 else{ 47 Fail[Next[root][i]]=root; 48 que.push(Next[root][i]); 49 } 50 } 51 while(!que.empty()){ 52 int now=que.front(); 53 que.pop(); 54 End[now]+=End[Fail[now]];//此題可重復計算,所以要加 55 for(int i=0;i<N;i++){ 56 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; 57 else{ 58 Fail[Next[now][i]]=Next[Fail[now]][i]; 59 que.push(Next[now][i]); 60 } 61 } 62 } 63 } 64 65 void solve(int n){ 66 memset(dp,-1,sizeof dp); 67 dp[0][0]=0; 68 for(int i=0;i<n;i++){ 69 for(int j=0;j<tot;j++){ 70 if(dp[i][j]==-1) continue; 71 for(int k=0;k<26;k++){ 72 int u=Next[j][k]; 73 if(dp[i][j]+End[u]>dp[i+1][u]){ 74 dp[i+1][u]=dp[i][j]+End[u]; 75 path[i+1][u]=path[i][j]+char(k+a); 76 }else if(dp[i][j]+End[u]==dp[i+1][u]){ 77 string str=path[i][j]; 78 str+=char(k+a); 79 if(str<path[i+1][u]) path[i+1][u]=str; 80 } 81 } 82 } 83 } 84 int ans=0,length=-1; 85 for(int i=0;i<=n;i++){ 86 for(int j=0;j<tot;j++){ 87 if(dp[i][j]>ans){ 88 ans=dp[i][j]; 89 length=i; 90 } 91 } 92 } 93 if(ans==0){ 94 printf("\n"); 95 return; 96 } 97 string str=""; 98 for(int j=0;j<tot;j++){ 99 if(dp[length][j]==ans&&(str>path[length][j]||str=="")) str=path[length][j]; 100 } 101 printf("%s\n",str.c_str()); 102 //printf("%d\n",ans); 103 } 104 105 }; 106 107 Trie ac; 108 char buf[101][15]; 109 int main(){ 110 int T; 111 scanf("%d",&T); 112 while(T--){ 113 ac.init(); 114 scanf("%d%d",&n,&m); 115 for(int i=1;i<=m;i++){ 116 scanf("%s",buf[i]); 117 } 118 for(int i=1;i<=m;i++) scanf("%d",val+i),ac.insert(buf[i],val[i]); 119 ac.build(); 120 ac.solve(n); 121 } 122 }

[hdu2296]Ring(AC自動機+dp)