hnu 12525 状态DP

City Merger
Time Limit: 60000ms, Special Time Limit:150000ms, Memory Limit:65536KB
Total submit users: 20, Accepted users: 17
Problem 12525 : No special judgement
Problem description
Recent improvements in information and communication technology have made it possible to provide municipal service to a wider area more quickly and with less costs. Stimulated by this, and probably for saving their not sufficient funds, mayors of many cities started to discuss on mergers of their cities.

 

There are, of course, many obstacles to actually put the planned mergers in practice. Each city has its own culture of which citizens are proud. One of the largest sources of friction is with the name of the new city. All citizens would insist that the name of the new city should have the original name of their own city at least as a part of it. Simply concatenating all the original names would, however, make the name too long for everyday use.

You are asked by a group of mayors to write a program that finds the shortest possible name for the new city that includes all the original names of the merged cities. If two or more cities have common parts, they can be overlapped. For example, if ``FUKUOKA", ``OKAYAMA", and ``YAMAGUCHI" cities are to be merged, ``FUKUOKAYAMAGUCHI" is such a name that include all three of the original city names. Although this includes all the characters of the city name ``FUKUYAMA" in this order, it does not appear as a consecutive substring, and thus ``FUKUYAMA" is not considered to be included in the name.

Input
The input is a sequence of datasets. Each dataset begins with a line containing a positive integer n (n≤14), which denotes the number of cities to be merged. The following n lines contain the names of the cities in uppercase alphabetical letters, one in each line. You may assume that none of the original city names has more than 20 characters. Of course, no two cities have the same name.
The end of the input is indicated by a line consisting of a zero.
Output
For each dataset, output the length of the shortest possible name of the new city in one line. The output should not contain any other characters.
Sample Input
3
FUKUOKA
OKAYAMA
YAMAGUCHI
3
FUKUOKA
FUKUYAMA
OKAYAMA
2
ABCDE
EDCBA
4
GA
DEFG
CDDE
ABCD
2
ABCDE
C
14
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
FFFFF
GGGGG
HHHHH
IIIII
JJJJJ
KKKKK
LLLLL
MMMMM
NNNNN
0
Sample Output
16
19
9
9
5
70
Problem Source

Fukuoka,2011

看到这道题的限时,1mins了,而且作为一个DP盲,就想到了暴搜,枚举所有情况~~可是想想还是太暴力了~~学一下状态DP吧~感谢小朋友给我讲了讲状态DP,其实还是用枚举所有情况,只是是用一个数字来表示当前状态,比如7,二进制数字就是111,那么就是前三位上都有(前三位是从右往左数),那么7的来源就是110,101,011这三种情况,然后用异或来表示状态~~具体还是看看课件吧~
这道题中dp[1<<n][n];一个表示当前状态,一个表示该字符串前面是哪个字符串。

一开始WA了好几次,有个细节误解题意了,以为比如是开头结尾有重复的才可以,WA的代码对于这组样例
3
abcd
b

c

输出就是6,但是其实包括包含的情况,所以输出应该是4~~有个去重的get函数,先去掉重复的~~

View Code
  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 using namespace std;
  7 const int INF=1000000000;
  8 int _map[15][15];
  9 int dp[1<<15][15];
 10 char str[15][25];
 11 int n,t,flag;
 12 int min(int a,int b)
 13 {
 14     return a<b?a:b;
 15 }
 16 //get函数看看有没有一个字符串是否是另外一个字符串的子串,去重操作
 17 bool get(int a,int b)
 18 {
 19     int len1=strlen(str[a]);
 20     int len2=strlen(str[b]);
 21     if(len1<len2)
 22     {
 23         a^=b^=a^=b;
 24         len1^=len2^=len1^=len2;
 25     }
 26 
 27     for(int i=0;i<=len1-len2;i++)
 28     if(strncmp(str[a]+i,str[b],len2)==0)
 29        return 1;
 30 
 31     return 0;
 32 }
 33 //str[b]连接在str[a]后面长度会增加多少
 34 int getlen(int a,int b)
 35 {
 36     int len1=strlen(str[a]);
 37     int len2=strlen(str[b]);
 38     for(int i=0;i<len1;i++)
 39     {
 40         if(str[a][i]==str[b][0])
 41         {
 42             int cnt=0;
 43             for(int j=i,k=0;j<len1;j++,k++)
 44             {
 45                 cnt++;
 46                 if(str[a][j]!=str[b][k])
 47                 {
 48                     cnt=0;break;
 49                 }
 50             }
 51             if(cnt!=0) return len2-cnt;
 52         }
 53     }
 54     return len2;
 55 }
 56 int dfs(int state,int u)
 57 {
 58     if(dp[state][u]!=INF)
 59     return dp[state][u];
 60 
 61     if(state==0)
 62     return dp[0][u]=0;
 63 
 64     for(int i=0;i<n;i++)
 65     {
 66         if(state&(1<<i))
 67         {
 68             int now=state^(1<<i);
 69             dp[state][u]=min(dp[state][u],dfs(now,i)+_map[u][i]);
 70         }
 71     }
 72     return dp[state][u];
 73 }
 74 int main()
 75 {
 76     while(scanf("%d",&n)!=EOF&&n)
 77     {
 78         getchar();
 79         for(int i=0;i<n;i++)
 80         {
 81             scanf("%s",str[i]);
 82             for(int j=0;j<i;j++)
 83             {
 84                 if(get(i,j))
 85                 {
 86                     if(strlen(str[i])>strlen(str[j]))
 87                     strcpy(str[j],str[i]);
 88                     i--;n--;
 89                 }
 90             }
 91         }
 92 
 93         for(int i=0;i<n;i++)
 94             for(int j=0;j<n;j++)
 95             _map[i][j]=getlen(i,j);
 96 
 97         for(int i=0;i<(1<<n);i++)
 98           for(int j=0;j<n;j++)
 99           dp[i][j]=INF;
100 
101         int res=INF;
102         int state=(1<<n)-1;
103         for(int i=0;i<n;i++)
104         {
105             res=min(res,dfs(state^(1<<i),i)+strlen(str[i]));
106         }
107         printf("%d\n",res);
108     }
109 }

 

 

 

posted @ 2012-09-06 23:53  _sunshine  阅读(298)  评论(0编辑  收藏  举报