大致题意:
要把n个字符串首尾相连成若干个环,如果把s1接到s2的后面可以得到一定的收获值,这个值等于s2的逆序 和s1的最长相同前缀的长度。求总收获值最大是多少。
大致思路:
看完题就感觉是KM二分图最大全匹配,匹配部分思路和hdu1853类似。感觉字符串部分的复杂度过高,以为有什么牛逼的算法,迟迟不敢下手敲,看了别人题解才发现暴力就行了。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int nMax=204; const int mMax=1005; const int inf=1<<29; int map[nMax][nMax]; int lx[nMax],ly[nMax]; int mapch[nMax]; int stack[nMax]; bool sy[nMax],sx[nMax]; int n,m,e,cnt; int find (int u){ int v,t; sx[u]=1; for(v=1;v<=m;v++){ if(sy[v]) continue; t=lx[u]+ly[v]-map[u][v]; if(t==0){ sy[v]=1; if(mapch[v]==-1||find(mapch[v])){ mapch[v]=u; return 1; } } else if(t<stack[v]) stack[v]=t; } return 0; } int KM(){ int i,j,k,d,sum=0; cnt=0; for(i=1;i<=m;i++) ly[i]=0; memset(mapch,-1,sizeof(mapch)); for(i=1;i<=n;i++){ lx[i]=-inf; for(j=1;j<=m;j++) if(map[i][j]>lx[i]) lx[i]=map[i][j]; } for(i=1;i<=n;i++){ for(j=1;j<=m;j++) stack[j]=inf; while(1){ for(k=1;k<=m;k++) sy[k]=0; for(k=1;k<=n;k++) sx[k]=0; if(find(i)) break; d=inf; for(k=1;k<=m;k++) if(!sy[k]&&stack[k]<d) d=stack[k]; for(k=1;k<=n;k++) if(sx[k]) lx[k]-=d; for(k=1;k<=m;k++) if(sy[k]) ly[k]+=d; else stack[k]-=d; } } for(i=1;i<=m;i++) if(mapch[i]!=-1&&map[mapch[i]][i]!=-inf){ sum+=map[mapch[i]][i]; } return sum; } char str[nMax][1003]; int maxpre(int a,int b){ int i,j; int ans=0; int la=strlen(str[a]); int lb=strlen(str[b]); for(i=0,j=lb-1;;){ if(i<la&&j>=0&&str[a][i]==str[b][j]){ i++; j--; ans++; } else break; } return ans; } int main(){ int i,j; while(scanf("%d",&n)!=EOF){ m=n; memset(map,0,sizeof(map)); for(i=1;i<=n;i++){ scanf("%s",str[i]); } for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(i==j)continue; map[i][j]=maxpre(i,j); } } printf("%d\n",KM()); } return 0; }