DNA Laboratory POJ - 1795 (状压dp+dfs)

Background 
Having started to build his own DNA lab just recently, the evil doctor Frankenstein is not quite up to date yet. He wants to extract his DNA, enhance it somewhat and clone himself. He has already figured out how to extract DNA from some of his blood cells, but unfortunately reading off the DNA sequence means breaking the DNA into a number of short pieces and analyzing those first. Frankenstein has not quite understood how to put the pieces together to recover the original sequence. 
His pragmatic approach to the problem is to sneak into university and to kidnap a number of smart looking students. Not surprisingly, you are one of them, so you would better come up with a solution pretty fast. 
Problem 
You are given a list of strings over the alphabet A (for adenine), C (cytosine), G (guanine), and T (thymine),and your task is to find the shortest string (which is typically not listed) that contains all given strings as substrings. 
If there are several such strings of shortest length, find the smallest in alphabetical/lexicographical order.

Input

The first line contains the number of scenarios. 
For each scenario, the first line contains the number n of strings with 1 <= n <= 15. Then these strings with 1 <= length <= 100 follow, one on each line, and they consist of the letters "A", "C", "G", and "T" only.

Output

The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the shortest (and smallest) string as described above. Terminate the output for the scenario with a blank line.

Sample Input

1
2
TGCACA
CAT

Sample Output

Scenario #1:
TGCACAT

题意:求所给字符能拼接的最短的字典序最小的窜

思路:将有没有选择这个窜进行状压,dp[s][i]表示已选s,且第一个是i的最短长度,然后一次往前推,不断更新第一个位置 的字符串,需要预处理出将i窜接到j窜的最小长度,cost[i][j]

最后,反向dfs即可得到答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=1e5+7;
#define inf 0x3f3f3f3f
int cost[30][30];
int dp[1<<15][20];
string s[30];
string ans;
int n;
void init()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(j==i) continue;
            if(s[i].find(s[j])!=string::npos)
            {
                s[j]=s[i];
            }
        }
    }
    stable_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)==s[j].substr(0,k))
                {
                    cost[i][j]=s[i].size()-k;
                }
            }
        }
    }
}
void dfs(int id,int sta)
{
    if(sta==0) return;
    int next=-1;
    string tmp;
    for(int i=0;i<n;i++)
    {
        if(id==i) continue;
        if(!(sta&(1<<i))) continue;
        if(dp[sta][id]==(dp[sta^(1<<id)][i]+cost[id][i]))
        {
            string t=s[i].substr(s[id].size()-cost[id][i],s[i].length());
            if(next==-1||tmp>t)
            {
                tmp=t;
                next=i;
            }
        }
    }
    if(next==-1) return;
    ans+=tmp;
    dfs(next,sta^(1<<id));
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T;
    int Case=0;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            cin>>s[i];
        }
        if(n==1) {cout<<s[0]<<endl<<endl;continue;}
        init();
        memset(dp,inf,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            dp[1<<i][i]=s[i].size();
        }
        int sta=(1<<n)-1;
        for(int s=0;s<=sta;s++)
        {
            for(int i=0;i<n;i++)
            {
                if(s&(1<<i)&&dp[s][i]!=inf)
                {
                    for(int j=0;j<n;j++)
                    {
                        if(i==j) continue;
                        if((s&(1<<j))==0)
                        {
                            dp[s|(1<<j)][j]=min(dp[s|(1<<j)][j],dp[s][i]+cost[j][i]);
                        }
                    }
                }
            }
        }
        int id=0;
        for(int i=1;i<n;i++)
        {
            if(dp[sta][i]<dp[sta][id])
            {
                id=i;
            }
        }
        ans=s[id];
        dfs(id,sta);
        printf("Scenario #%d:\n",++Case);
        cout<<ans<<endl<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值