您的位置:首页 > 其它

POJ - 1795 DNA Laboratory 状压DP + dfs

2017-08-09 23:44 302 查看
传送门:POJ1795

题意: 给出n个字符串,问包含这n个字符串的最短的总串字典序最小是多少。

思路:思路来自:http://blog.csdn.net/qq_29169749/article/details/54755026

dp[i][s]:=在所有字符串选取情况为s的状态下,最前面的字符串为i号字符串的最小长度。依次枚举下一个字符串可得状态转移方程 dp[i][s | 1 << i] = min(dp[i][s | 1<< i], dp[j][s] + cost[i][j]);

cost[i][j] := i字符串拼接到j字符串前面所需要的最小花费

最后再dfs往回找字典序最小的答案。

预处理时注意将被包含的字符串去掉。

代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
const int MAXN=100010;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
string s[20];
int cost[20][20];//cost[i][j]将i字符串接到j字符串前面所需要的最小花费
void init(int &n)
{
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(s[i].find(s[j]) != string::npos)
s[j] = s[i];
sort(s, s + n);
n = unique(s, s + n) - s;
memset(cost, 0, sizeof(cost));
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
if(i == j) continue;
int len = min(s[i].size(), s[j].size());
for(int k = 0; k < len; k++)
{
if(s[i].substr(s[i].size() - k, k) == s[j].substr(0, k))
cost[i][j] = s[i].size() - k;
}
}
}
int dp[20][1 << 16], n;
string ans;
void dfs(int id, int st)
{
if(st == 0) return ;
string tmp = "zzzz";
int nxt = -1;
for(int i = 0; i < n; i++)
{
if(i != id && (st & 1 << i) && (dp[id][st] == dp[i][st & ~(1 << id)] + cost[id][i]))
{
if(s[i].substr(s[id].size() - cost[id][i]) < tmp)
tmp = s[i].substr(s[id].size() - cost[id][i]), nxt = i;
}
}
if(nxt != -1)
ans += tmp;
dfs(nxt, st & ~(1 << id));
}
int main()
{
int T;
cin >> T;
for(int kase = 1; kase <= T; kase++)
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> s[i];
init(n);
memset(dp, inf, sizeof(dp));
for(int i = 0; i < n; i++)
dp[i][1 << i] = s[i].size();
for(int k = 0; k < (1 << n); k++)
{
for(int j = 0; j < n; j++)
if((k & 1 << j) && dp[j][k] != inf)
{
for(int i = 0; i < n; i++)
{
dp[i][k | 1 << i] = min(dp[i][k | 1 << i], dp[j][k] + cost[i][j]);
}
}

}
int id = 0;
for(int i = 0; i < n; i++)
{
if(dp[id][(1 << n) - 1] > dp[i][(1 << n) - 1])
id = i;
}
ans = s[id];
dfs(id, (1 << n) - 1);
printf("Scenario #%d:\n", kase);
cout << ans << endl << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: