HNU 省赛选拔热身赛City Merger解题报告

给出不超过14个长度不超过20的字符串,要求出一个包含所有字符串的长字符串的最短的长度,根据题目数据范围可以知道要用状态DP,每个二进制位表示一个字符串,而且需要用二维的,dp[i][j]表示以j为开头的剩下的状态为i的最优值,转移方程也很好写。

View Code
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N 15
  5 #define inf 0x7fffffff
  6 using namespace std;
  7 int dp[1<<15][N];
  8 char str[N][25];
  9 int map[N][N];
 10 int min(int a,int b)
 11 {
 12     return a<b?a:b;
 13 }
 14 bool get(int i,int j)
 15 {
 16     if(strcmp(str[i],str[j])==0)
 17     return true;
 18     int len1=strlen(str[i]);
 19     int len2=strlen(str[j]);
 20     int l,k,p;
 21     for(k=0;k<=len1-len2;k++)
 22     {
 23         for(p=0;p<len2&&k+p<len1;p++)
 24         if(str[i][k+p]!=str[j][p])
 25         break;
 26         if(p==len2)
 27         return true;
 28     }
 29     for(k=0;k<=len2-len1;k++)
 30     {
 31         for(p=0;p<len1&&k+p<len2;p++)
 32         if(str[i][p]!=str[j][k+p])
 33         break;
 34         if(p==len1)
 35         return true;
 36     }
 37     return false;
 38 }
 39 int getlen(int i,int j)//两个字符串连接增加的长度
 40 {
 41     int l,k,p;
 42     int len1=strlen(str[i]);
 43     int len2=strlen(str[j]);
 44     int minlen=min(len1,len2);
 45     for(l=minlen;l>=0;l--)
 46     {
 47         for(k=len1-l,p=0;k<len1&&p<len2;k++,p++)
 48         if(str[i][k]!=str[j][p])
 49         break;
 50         if(k==len1||p==len2)
 51         return len2-l;
 52     }
 53 }
 54 int n;
 55 int dfs(int state,int k)//记忆化搜索的部分
 56 {
 57     if(dp[state][k]!=inf)
 58     return dp[state][k];
 59     if(state==0)
 60     return dp[0][k]=0;
 61     int i,j,sta;
 62     for(i=0;i<n;i++)
 63     {
 64         if(state&(1<<i))
 65         {
 66             sta=state^(1<<i);
 67             dp[state][k]=min(dp[state][k],dfs(sta,i)+map[k][i]);
 68         }
 69     }
 70     return dp[state][k];
 71 }
 72 int main()
 73 {
 74     int i,j;
 75     int minn;
 76     while(scanf("%d",&n)&&n)
 77     {
 78         for(i=0;i<n;i++)
 79         {
 80             scanf("%s",str[i]);
 81             for(j=0;j<i;j++)
 82             {
 83                 if(get(i,j))
 84                 {
 85                     if(strlen(str[i])>strlen(str[j]))//有字符串被另一个包含的时候,把短的字符串直接覆盖掉
 86                     strcpy(str[j],str[i]);
 87                     i--;
 88                     n--;
 89                 }
 90             }
 91         }
 92         for(i=0;i<n;i++)
 93         for(j=0;j<n;j++)
 94         {
 95             map[i][j]=getlen(i,j);
 96         }
 97         for(i=0;i<(1<<n);i++)
 98         for(j=0;j<n;j++)
 99         dp[i][j]=inf;
100         int state=(1<<n)-1;
101         minn=inf;
102         for(i=0;i<n;i++)
103         {
104             minn=min(minn,dfs(state^(1<<i),i)+strlen(str[i]));
105         }
106         printf("%d\n",minn);
107     }
108     return 0;
109 }

 

posted @ 2012-09-04 19:58  zhenhai  阅读(172)  评论(0编辑  收藏  举报