http://acm.hdu.edu.cn/showproblem.php?pid=3722
KM 先求出任意两个字符串前后匹配的值 然后KM求最大匹配
越来越发现 图论题的关键在于建图呀
代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<vector> #include<set> #include<queue> #include<map> #include<string> #include <iomanip> using namespace std; const int INF=0x3f3f3f3f; const int N=205; const int M=1005; char stmp[N][M]; int L[N]; int dist[N][N]; int f[N]; bool lv[N],rv[N]; int a[N],b[N]; bool dfs(int x,int n) { lv[x]=true; for(int i=1;i<=n;++i) { if(!rv[i]&&a[x]+b[i]==dist[x][i]) { rv[i]=true; if(f[i]==-1||dfs(f[i],n)) { f[i]=x; return true; } } } return false; } int Km(int n) { memset(f,-1,sizeof(f)); memset(b,0,sizeof(b)); for(int i=1;i<=n;++i) { a[i]=-1; for(int j=1;j<=n;++j) a[i]=max(a[i],dist[i][j]); } for(int l=1;l<=n;++l) { while(true) { memset(lv,false,sizeof(lv)); memset(rv,false,sizeof(rv)); if(dfs(l,n)) break; int d=INF; for(int i=1;i<=n;++i) { if(lv[i]) for(int j=1;j<=n;++j) { if(!rv[j]) d=min(d,a[i]+b[j]-dist[i][j]); } } for(int i=1;i<=n;++i) { if(lv[i]) a[i]-=d; if(rv[i]) b[i]+=d; } } } int ans=0; for(int i=1;i<=n;++i) { if(f[i]!=-1) ans+=dist[f[i]][i]; } return ans; } int main() { //freopen("data.txt","r",stdin); int n; while(scanf("%d",&n)!=EOF) { getchar(); for(int i=1;i<=n;++i) {gets(stmp[i]);L[i]=strlen(stmp[i]);} memset(dist,0,sizeof(dist)); for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { if(i==j) continue; int l1=L[i]-1; int l2=0; for(;l1>=0&&l2<L[j];--l1,++l2) { if(stmp[i][l1]!=stmp[j][l2]) break; } dist[i][j]=l2; } } printf("%d\n",Km(n)); } return 0; }