间间断断做了一个星期、、、、终于过了,哈哈哈哈·,这个思路是把字符串都看成一个节点,选定其中一个作为起点,周游一次,不返回原点的最小距离,其中距离由字符串之间的匹配程度决定,也就是一个TSP吧
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
using namespace std;
const int maxn=15,len=30,inf=40000;
int t,n;
char s[maxn][len];
int a[maxn][maxn],b[maxn][maxn];
int d[maxn][1<<maxn],v[maxn][1<<maxn];
//char con[5]="AGCT";生成随机字符串要用到
void handle(int b[maxn][maxn],int a[maxn][maxn],int m)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
b[i][j]=a[(i+m)%n][(j+m)%n];
}
int check(int m,int n)
{
int temp=strlen(s[n]),flag=1;
for(int i=0;i<strlen(s[m]);i++)
{
flag=1;
for(int j=0,k=i;k<strlen(s[m]);k++,j++)
if(*(s[m]+k)!=*(s[n]+j))
{
flag=0;
break;
}
if(flag)
{
temp=i;
break;
}
}
if(flag) return strlen(s[n])-strlen(s[m])+temp;
return strlen(s[n]);
}
int dp(int j,int s)
{
if(v[j][s]) return d[j][s];
v[j][s]=1;
for(int k=1;k<n;k++)//???
if(s&(1<<(k-1))&&(k!=j))
d[j][s]=min(d[j][s],dp(k,s^(1<<(j-1)))+b[k][j]);//这里括号括错了、、Debug了差不多一天、、、被虐得死去活来、、、、
return d[j][s];
}
int main()
{
// 这几行为生成满足条件的随机数写入"test.txt"中,然后再讲"test.txt"改为读状态,输出结果放在"out.txt"中并将结果利用这个Debug会方便很多,网上学的一招
// freopen("test.txt","w",stdout);
// srand((unsigned)time(NULL));
// t=rand()%10+1;
// printf("%d\n",t);
// for(int k=0;k<t;k++)
// {
// n=rand()%10+1;
// printf("%d\n",n);
// for(int i=0;i<n;i++)
// {
// int len=rand()%20+1;
// for(int j=0;j<len;j++)
// {
// int pos=rand()%4;
// printf("%c",con[pos]);
// }
// printf("\n");
// }
// }
//freopen("test.txt","r",stdin);//读入"test.txt"
//freopen("out.txt","w",stdout);//输出结果
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
if(n==1)
{
scanf("%s",s[0]);//一开始忘了加这一行,直接printf后就continue,结果2了、、、、
printf("%d\n",strlen(s[0]));
continue;
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=inf;
//该循环构造以字符串作为节点的图,check(i,j)算出s[i]到s[j]的距离
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
for(int j=0;j<i;j++)
{
a[i][j]=check(i,j);
a[j][i]=check(j,i);
}
}
int realmin=inf;
for(int m=0;m<n;m++)
{
int minnum=inf;
memset(v,0,sizeof(v));
handle(b,a,m);//选定字符串s[m]作为起点
for(int i=0;i<n;i++)
for(int s0=1;s0<(1<<n);s0++)
d[i][s0]=inf;//初始化d
for(int i=1;i<n;i++)
d[i][1<<(i-1)]=b[0][i];//对于每个从起点第一步走到i的选择,距离为b[0][i]
for(int i=1;i<n;i++)
for(int s0=1;s0<(1<<(n-1));s0++)
{
if(s0&(1<<(i-1)))
{
for(int j=1;j<n;j++)
{
if(s0&(1<<(j-1)))
{
if(i!=j)
d[i][s0]=min(d[i][s0],dp(j,s0^(1<<(i-1)))+b[j][i]);//递归的记忆化搜索,一开始直接写成了d[j][s0^(1<<(i-1))]+b[j][i],囧死、、、、
}
}
}
}
int len=strlen(s[m]);
// printf("len%d:%d\n",m,len); //自己调试用的输出,可无视
for(int i=1;i<n;i++)
{
minnum=min(minnum,d[i][(1<<(n-1))-1]);//反省一下,为什么能力不够、、、、
// printf("min %d:%d\t",i,d[i][(1<<(n-1))-1]);//无视
}
// printf("")//无视
// printf("\n");//无视
realmin=min(realmin,minnum+len);
}
printf("%d\n",realmin);
}
return 0;
}