POJ 1795 DNA Laboratory(状压DP)

 

【题目链接】 http://poj.org/problem?id=1795

 

【题目大意】

  给出n个字符串,求一个最小长度的串,该串包含给出的所有字符串。
  要求长度最小且字典序最小。

 

【题解】

  dp[i][s]表示包括s集合字符串的第i个字符串为开头的最小值
  从后往前贪心得到最小值,然后从前往后搜索得出最小字典序的答案

 

【代码】

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N=17,INF=0x3f3f3f3f;
string str[N],ans;
int T,Cas=0,n,dp[N][1<<N],cost[N][N];
void init(){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(i!=j&&str[i].find(str[j])!=string::npos)str[j]=str[i];
        }
    }sort(str,str+n);
    n=unique(str,str+n)-str;
    memset(cost,0,sizeof(cost));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)if(i!=j){
            int len=min(str[i].length(),str[j].length());
            for(int k=0;k<=len;k++){
                if(str[i].substr(str[i].length()-k)==str[j].substr(0,k)){
                    cost[i][j]=str[i].length()-k;
                }
            }
        }
    }
}
void dfs(int id,int s){
    if(s==0)return;
    string tmp; int nxt=-1;
    for(int i=0;i<n;i++)if(i!=id&&(s>>i&1)){
        if(dp[id][s]==dp[i][s&~(1<<id)]+cost[id][i]){
            string t=str[i].substr(str[id].length()-cost[id][i],str[i].length());
            if(nxt==-1||t<tmp){tmp=t;nxt=i;}
        }
    }ans+=tmp;
    dfs(nxt,s&~(1<<id));
}
int main(){
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=0;i<n;i++)cin>>str[i];
        if(n>1){
            init();
            for(int i=0;i<=n;i++)fill(dp[i],dp[i]+(1<<n),INF);
            for(int i=0;i<n;i++)dp[i][1<<i]=str[i].length();
            for(int s=0;s<1<<n;s++){
                for(int j=0;j<n;j++)if(dp[j][s]!=INF&&(s>>j&1)){
                    for(int i=0;i<n;i++)if(!(s>>i&1)){
                        dp[i][s|1<<i]=min(dp[i][s|1<<i],dp[j][s]+cost[i][j]);
                    }
                }
            }int id=0;
            for(int i=1;i<n;i++){
                if(dp[i][(1<<n)-1]<dp[id][(1<<n)-1])id=i;
            }ans=str[id];
            dfs(id,(1<<n)-1);
        }else ans=str[0];
        cout<<"Scenario #"<<++Cas<<":"<< endl;  
        cout<<ans<<endl<<endl; 
    }return 0;
}
posted @ 2017-02-08 09:55  forever97  阅读(142)  评论(0编辑  收藏  举报