Traveling Salesman Problem
Solve:暴力解法复杂度为O(N!)这个是难以承受的,可以用朴素的DP划分思想达到O(N^2*2^N)。
N个节点有2^N个子集,记录集合中以v为结束点的集合个数为N*2^N个。
预处理出每个字符串和其他串的最大匹配长度,跑一遍 TSP。
code:
View Code
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <cstring> using namespace std; const int MM = 110; #define maxint 0x3f3f3f3f int N; int d[1<<11][11]; char str[MM]; int len[MM][MM]; int fail[MM]; char ch[21][MM]; vector<int>edge[MM]; int max(int x,int y) {return x>y?x:y;} int min(int x,int y) {return x>y?y:x;} void get_next(int m) { int i,j=0,k; fail[1]=0; for(i=2;i<=m;i++) { while(j>0 && str[j+1]!=str[i]) j=fail[j]; if(str[j+1]==str[i]) j++; fail[i]=j; } } int kmp(int n,int m,int id) { int i,j=0,k; for(i=1;i<=m;i++) { while(j>0 && str[j+1]!=ch[id][i]) j=fail[j]; if(str[j+1]==ch[id][i]) j++; if(j==n) return n; } return 0; } int cal(int s1,int s2) { int i,j,k,n,m,ans=0; n=strlen(ch[s1]+1); m=strlen(ch[s2]+1); for(i=1;i<=n;i++) { for(j=i;j<=n;j++) str[j-i+1]=ch[s1][j]; str[n-i+2]='\0'; // get_next(n-i+1); // ans=max(kmp(n-i+1,m,s2),ans); for(j=1;j<=(n-i+1);j++) { if(str[j]!=ch[s2][j]) break; } if(j>(n-i+1)) return n-i+1; } return 0; } void get_data() { int i,j,k; scanf("%d",&N); for(i=1;i<=N;i++) scanf("%s",ch[i]+1); memset(len,0,sizeof(len)); for(i=1;i<=N;i++) { for(j=1;j<=N;j++) { len[i][j]=cal(i,j); } } } void solve() { int i,j,k,n=(1<<N)-1,mask; memset(d,maxint,sizeof(d)); for(i=0;i<N;i++) d[1<<i][i]=len[i+1][i+1]; for(i=1;i<=n;i++) { for(j=0;j<N;j++) { if(i&(1<<j)) { mask=i&~(1<<j); for(k=0;k<N;k++) { if(mask&(1<<k)) d[i][j]=min(d[i][j],d[mask][k]+strlen(ch[j+1]+1)-len[k+1][j+1]); // if(i==3&&j==1) printf("%d\n",d[1][0]); } } } } int ans=maxint; for(i=0;i<N;i++) ans=min(ans,d[n][i]); printf("%d\n",ans); } int main() { int ca; scanf("%d",&ca); while(ca--) get_data(),solve(); return 0; }