poj2817(N!的状压DP)

来源:互联网 发布:ug4数控车床编程 编辑:程序博客网 时间:2024/04/28 09:43

题意:将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;}


0 0
原创粉丝点击