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;
}