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
- poj2817(N!的状压DP)
- poj2817(状态压缩dp基础题)
- DP poj2817 WordStack
- poj2817状态压缩DP
- 状态dp poj2817
- poj2817 状态dp(二进制存储)+记忆化搜索
- poj2817
- POJ2817 WordStack
- n的m划分 dp
- N-K集合(dp)
- 【tyvj4089】n^2(dp)
- POJ2817——WordStack
- [Spoj]严格n元树(dp)
- 数位dp(求1-n中数字1出现的个数)
- [ACM] hdu 3555 Bomb (数位DP,统计1-N中含有“49”的总数)
- POJ 3670 Eating Together (①O(n)的dp,②最长字段和)
- HDU 5569 长度为n的上升子序列个数d (大数模板+DP)
- 求n个中选m个的方案数(dp)
- 【笔记】21天学通C++(第六版)_笔记二
- SSH
- 时间复杂度的概念
- ORACLE修改数据结构语句
- linux ps
- poj2817(N!的状压DP)
- 题目1116:加减乘除
- Eyou Mail System Remote Code Execution
- 软件质量评价标准
- Android入门
- ORACLE的SQL集锦
- zoj 3742 Bellywhite's Algorithm Homework
- hdu1157解题报告
- 简单的JDK环境配置