http://www.cnblogs.com/PureMilk/archive/2008/07/17/1245085.html#2163586
思想参考的这位的博客,写得很详细,十分感谢她(他),这也是我的第一道状态dp,代码是自己敲的,开始的时候,过不了样例,发现位运算的条件弄错了,还有num数组打表弄错了,改后就1A了。
上面的博客写得很详细,只稍微补充一下(补充在代码的注释中了),其它就看这个博客就行了。
/* 一个单词有就为1,没有就为0,于是用一个二进制序列存储哪些单词有或者没有, 将这个二进制序转化成十进制数,这样就用一个整数存储状态了 (此处单说有或者没有,可能会有点不好理解,下面会继续提到) */ #include <cmath> #include <iostream> using namespace std; #define MAX(a, b) a>b?a:b const int size = 11; int num[size][size], dp[1050][size]; char word[size][size]; int len[size], n; void calNum(int n, int m) { int i, j, res1, res2, max1, max2; for(max1 = i = 0; i < len[n]; i++) { for(res1 = j = 0; j < len[m] && j + i < len[n]; j++) if(word[m][j] == word[n][j+i]) res1++; if(res1 > max1) max1 = res1; } for(max2 = i = 0; i < len[m]; i++) { for(res2 = j = 0; j < len[n] && j + i < len[m]; j++) if(word[n][j] == word[m][j+i]) res2++; if(res2 > max2) max2 = res2; } num[n][m] = num[m][n] = MAX(max1, max2); } int dfs(int curr, int last) { if(dp[curr][last] > 0) return dp[curr][last]; if(curr == 0) return 0; int tmp, max = 0, next = (curr&(~(1<<last)));//将最后一个单词的状态变为0(即将有改成没有) for(int i = 0; i < n; i++) if( ((1<<i)&next) != 0 ) //判断第i个单词的状态是否为1,若为1则将其放在当前的最后一个单词前面 { tmp = dfs(next, i) + num[last][i]; if(tmp > max) max = tmp; } return (dp[curr][last] = max); } int main() { int i, j, state; while(scanf("%d", &n) && n > 0) { memset(dp, 0, sizeof(dp)); state = (int)pow(2.0, n*1.0); /*state的值是表示所有单词都有的时候的状态的十进制整数加上1, 例如:样例中5个单词都有的状态为11111,即31,而state为2的5次方,即32 */ for(i = 0; i < n; i++) { scanf("%s", word[i]); len[i] = strlen(word[i]); } for(i = 0; i < n; i++)//打表num数组 for(j = i+1; j < n; j++) calNum(i, j); int max = 0, tmp; for(i = 0; i < n; i++) { tmp = dfs(state-1, i); //初始的时候,所有单词都有,所以初始状态为state-1 if(tmp > max) max = tmp; } printf("%d\n", max); } return 0; }