DNA Laboratory POJ - 1795

原题链接

考察:状压dp+dfs寻找路径

思路:

        重复覆盖问题.参考愤怒的小鸟的思路,我们需要两两构造一个包含两个字符串a,b的DNA序列,然后要分a在前面与b在前面两种情况.

        本蒟蒻一开始想的是定义结构体String,再定义结构体内部的st(二进制标记哪些串被标记),构造后的具体字符串s.每个状态f都要记录当前状态的最优字符串.但实际上没必要.这道题是属于倒序输出具体方案.并且本道题并不需要构造具体字符串,因为构造后的字符串含有字符串a,b,c....如果构造后能包含字符串d,说明a,b,c就存在一个字符串能包含d或被d包含.所以一定不存在构造新字符串后还能包含某个其他字符串的情况.

         所以可以定义f[i][j]为i状态下,首字符串为j的最短长度.f[i][j] = f[i-(1<<j)][k]+cost[j][k](表示把j放在k前面的花费).可用unique去掉被包含的字符串.

        计算cost就是后缀匹配前缀...可以用substr计算,不记得建议复习单词接龙这道题....

        最后倒序输出方案的时候,不一定是在前面的字典序一定最小,比如当前后缀CAAB 匹配它的AABX与ABC.按排序是AABX在前,但是接ABC字典序更小.所以需要去掉重叠部分比较.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 15,M = 110;
 7 int n,cost[N][N],f[1<<N][N];//cost[i][j]表示将i放在j前面的花费 
 8 string s[N],res;//重复覆盖问题 
 9 void init()//前后缀匹配 :substr 
10 {
11     memset(cost,0,sizeof cost);
12     for(int i=0;i<n;i++)
13       for(int j=0;j<n;j++)
14         if(s[i].find(s[j])!=s[i].npos) s[j] = s[i];
15     sort(s,s+n);//按序号字典序最小 
16     n = unique(s,s+n)-s;//去掉没必要存在的s 
17     for(int i=0;i<n;i++)
18       for(int j=0;j<n;j++)
19       {
20           if(i==j) continue;
21           int sz = min(s[i].size(),s[j].size()),k;
22           for(k=sz;k>=0;k--)
23             if(s[i].substr(s[i].size()-k,k)==s[j].substr(0,k)) 
24             {
25                 cost[i][j] = s[i].size()-k;
26                 break;
27           }
28       }
29 }
30 void solve()
31 {
32     memset(f,0x3f,sizeof f);
33     for(int i=0;i<n;i++) f[1<<i][i] = s[i].size();
34     for(int i=1;i<1<<n;i++)
35       for(int j=0;j<n;j++)
36         if(i>>j&1)
37           for(int k=0;k<n;k++)
38             if(j!=k&&(i>>k&1))
39                 f[i][j] = min(f[i-(1<<j)][k]+cost[j][k],f[i][j]);
40 }
41 void dfs(int st,int idx)
42 {
43     if(!st) return;
44     int now = st-(1<<idx),v = -1;
45     string temp = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
46     for(int i=0;i<n;i++)
47       if((now>>i&1)&&f[now][i]+cost[idx][i]==f[st][idx])
48       {
49            string t = s[i].substr(s[idx].size()-cost[idx][i]);
50            if(t<temp)
51              temp = t,v = i;
52       } 
53     if(v!=-1)
54     {
55         res+=temp;
56         dfs(now,v);
57     }    
58 }
59 int main()
60 {
61     int T,kcase = 0;
62     scanf("%d",&T);
63     while(T--)
64     {
65         if(kcase) printf("\n");
66         scanf("%d",&n);
67         for(int i=0;i<n;i++) cin>>s[i];
68         init();
69         solve();
70         int ans = 0x3f3f3f3f;
71         for(int i=0;i<n;i++) ans = min(ans,f[(1<<n)-1][i]);
72         for(int i=0;i<n;i++)
73            if(f[(1<<n)-1][i]==ans)
74            {
75                    res = s[i];
76                    dfs((1<<n)-1,i);
77                    break;
78            }
79         printf("Scenario #%d:\n%s\n",++kcase,res.c_str());
80     }
81     return 0;
82 }

 

posted @ 2021-04-04 10:01  acmloser  阅读(54)  评论(0编辑  收藏  举报