zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    车牌号验证正则验证
    人民币转大写
    Base64 格式图片上传至服务器
    郭博分析modbus主机模式
    解决小BUG的罗列
    写flash时为什么需要先擦除?
    C语言的很吊的printf-----来自一个C语言竞赛题目
    ( # #@ ## 在define中的应用)或( 连接两个字符串或者两个数字、强制转化成单引号、强制转化成双引号 )附加字符串强制转化成数字
    IAR无法goto的解决办法
    link list
  • 原文地址:https://www.cnblogs.com/forever97/p/poj1795.html
Copyright © 2011-2022 走看看