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; }
愿你出走半生,归来仍是少年