题意:将n个长度最长为10的字符串排列n行,上下对齐时候可以任意平移每一行,将每一行与上一行对齐位置相同的字符数加起来,问最多总共能有多少个。将最终数量输出。
例:
5 abc bcd cde aaa bfcde的结果展示如下:
aaa abc bcd cde bfcde
解法:方法是状态压缩记忆化搜索。以前做的状态压缩都是对于解集是2^n数量级形式的,做这道题最大的收获就是知道了对于N!数量级形式的问题如何进行状压了。在这道题中,首先求出两两字符串之间的最大匹配数,结果放在num[i][j]二维数组中,用于以后O(1)调用。状压时sum的每个二进制位的0和1分别表示相应字符串在与不在这个集合中。ans[sum][bit]表示在sum表示的字符串集合中以第bit的那个字符串结束的最大值(第bit字符串一定是在sum集合中的)。转移的时候就是枚举倒数第二结尾字符串了。祥见代码。不过这题由于数据太小,完全暴力枚举10!的排列也是可行的,感觉题的数据出的不太合理,如果给到20左右卡掉暴力就好了。后面附上暴力过的代码。状压0ms,暴力300+ms。
状压代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string.h>
using namespace std;
char s[10][11];
char num[10][10];
char ans[1024][10];
int n;
void help()
{
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int len1=strlen(s[i]);
int len2=strlen(s[j]);
for(int k=0;k<len1;k++)
{
int tool=0;
for(int h=0;h+k<len1&&h<len2;h++)
if(s[i][k+h]==s[j][h])
tool++;
num[i][j]=max(int(num[i][j]),tool);
}
for(int k=0;k<len2;k++)
{
int tool=0;
for(int h=0;h+k<len2&&h<len1;h++)
if(s[i][h]==s[j][h+k])
tool++;
num[i][j]=max(int(num[i][j]),tool);
}
num[j][i]=num[i][j];
}
}
int find(int sum,int bit)
{
if(ans[sum][bit]!=-1)
return ans[sum][bit];
int tool=0;
for(int i=0;i<n;i++){
if(i!=bit&&(sum&(1<<i))){
tool=max(tool,find(sum-(1<<bit),i)+num[bit][i]);
}
}
return ans[sum][bit]=tool;
}
int main()
{
while(scanf("%d",&n)==1)
{
if(n==0)
break;
memset(ans,-1,sizeof ans);
memset(num,0,sizeof num);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
help();
for(int i=0;i<n;i++)
ans[(1<<i)][i]=0;
int tool=0;
int t=(1<<n)-1;
for(int i=0;i<n;i++){
tool=max(tool,find(t,i));
}
printf("%d\n",tool);
}
return 0;
}
暴力代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string.h>
#include <algorithm>
using namespace std;
char s[12][12];
int num[12][12];
int ans[1200][12];
int n;
void help()
{
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int len1=strlen(s[i]);
int len2=strlen(s[j]);
for(int k=0;k<len1;k++)
{
int tool=0;
for(int h=0;h+k<len1&&h<len2;h++)
if(s[i][k+h]==s[j][h])
tool++;
num[i][j]=max(num[i][j],tool);
}
for(int k=0;k<len2;k++)
{
int tool=0;
for(int h=0;h+k<len2&&h<len1;h++)
if(s[i][h]==s[j][h+k])
tool++;
num[i][j]=max(num[i][j],tool);
}
num[j][i]=num[i][j];
}
}
int arrange[12];
int main()
{
while(scanf("%d",&n)==1)
{
if(n==0)
break;
memset(ans,-1,sizeof ans);
memset(num,0,sizeof num);
for(int i=0;i<n;i++)
scanf("%s",s[i]),arrange[i]=i;
help();
int tool=0;
for(int i=0;i<n-1;i++)
tool+=num[arrange[i]][arrange[i+1]];
while(next_permutation(arrange+0,arrange+n))
{
int t=0;
for(int i=0;i<n-1;i++)
t+=num[arrange[i]][arrange[i+1]];
tool=max(tool,t);
}
cout<<tool<<endl;
}
return 0;
}