题目链接: http://poj.org/problem?id=2817
题意: 给出n个字符串,一个排列使得相邻字符串之间的共同字母总数最多,这里的字母必须是一一对应的;
可以加空格。比如abc 和 asc,可以有很多种组合方式;如:
abc abc abc _abc __abc ___abc
asc _ asc __ asc asc asc asc
真心觉英语水平弱爆了,理解错了若干次。开始我以为是lcs,错。改,我又弱弱的以为要保持队形。
分析: 直接预处理出串之间的共同字母的最大数,然后就是简单的状态压缩dp
dp[news][j] = max(dp[news][j], dp[s][i] + dist[i][j] );
dp[s][i] 表示经过s里的所有点,并以i为结束点;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
template<class T>
void max( T &a, T b ) { if(a < b) a = b; }
const int maxn = 11;
int n;
int dist[maxn][maxn];
int dp[1<<maxn][maxn];
char str[maxn][maxn];
int count( int x, int y ) {
int ans = 0;
int len_x = strlen(str[x]);
int len_y = strlen(str[y]);
for ( int i=0; i<10; ++i ) {
int cnt = 0;
for ( int j=0; j+i<len_y && j<len_x; ++j )
if(str[x][j] == str[y][j+i] ) ++cnt;
max(ans, cnt);
cnt = 0;
for ( int j=0; j+i<len_x && j<len_y; ++j )
if(str[x][j+i] == str[y][j] ) ++cnt;
max(ans, cnt);
}
return ans;
};
int main( ) {
while( scanf("%d", &n), n>0 )
{
for ( int i=0; i<n; ++i )
scanf ("%s", str[i]);
for ( int i=0; i<n; ++i )
for ( int j=i+1; j<n; ++j )
dist[i][j] = dist[j][i] = count(i, j);
memset (dp, 0, sizeof dp);
int full = 1<<n, ans = 0;
for ( int s=1; s<full; ++s ) {
for ( int i=0; i<n; ++i ) if(s&(1<<i) )
{
for ( int j=0; j<n; ++j ) if(!(s&(1<<j))){
int news = s^(1<<j);
max(dp[news][j], dp[s][i]+ dist[i][j] );
max(ans, dp[news][j]);
}
}
}
printf ("%d\n", ans);
}
};
0ms无压力,复杂度0((1<<n)*n*n)。