题目链接:http://poj.org/problem?id=2192
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 18658 | Accepted: 6651 |
Description
Input
Output
Sample Input
3 cat tree tcraete cat tree catrtee cat tree cttaree
Sample Output
Data set 1: yes Data set 2: yes Data set 3: no
Source
题目大意:
给出两串,从两个串取出字符重新组合,看能否组成第三个串。要求:从第一个串取出的字符在第三个串中的顺序不变,第二个串取出的字符在第三个串中的顺序也不变。
算法分析:
此题深搜和DP都能解决:
深搜的话需要几个强有力剪枝条件
1、 第三个串最后一个字符要么是串1的最后一个字符,要么是串2的最后一个字符
2、 按照串1的顺序对串3进行搜索,若不匹配则该字符必是串2的下一个字符。
参考来源:http://www.cnblogs.com/yu-chao/archive/2012/02/26/2369052.html
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 char first[202],second[202],third[402],Left[401]; 6 int sign[402]; 7 bool flag; 8 int check() 9 { 10 int i,count=0; 11 int k=strlen(third); 12 for(i=0;i<k;i++) 13 if(!sign[i]) Left[count++]=third[i]; 14 Left[count]=‘\0‘; 15 if(strcmp(Left,second)==0) return 1; 16 return 0; 17 } 18 int dfs(int f,int s,int t) 19 { 20 if(f>=strlen(first)) 21 { 22 if(check()) flag=true; 23 return 0; 24 } 25 if(flag) return 0; 26 if(first[f]==third[s]) 27 { 28 sign[s]=1; 29 if(s<strlen(third)) dfs(f+1,s+1,t); 30 sign[s]=0; 31 } 32 else 33 { 34 if(third[s]!=second[t]) return 0;//剪枝2 35 } 36 if(!flag && s<strlen(third)) dfs(f,s+1,t+1); 37 return 0; 38 } 39 int main() 40 { 41 int len1,len2,len3,Case,count=0; 42 scanf("%d",&Case); 43 while(Case--) 44 { 45 count++; 46 flag=false; 47 scanf("%s %s %s",first,second,third); 48 memset(sign,0,sizeof(sign)); 49 50 len1=strlen(first); 51 len2=strlen(second); 52 len3=strlen(third); 53 54 if(len1+len2!=len3) 55 { 56 printf("Data set %d: no\n",count); 57 continue; 58 } 59 if(third[len3-1]!=first[len1-1] && third[len3-1]!=second[len2-1])// 剪枝1 60 { 61 printf("Data set %d: no\n",count); 62 continue; 63 } 64 dfs(0,0,0); 65 if(flag) 66 printf("Data set %d: yes\n",count); 67 else 68 printf("Data set %d: no\n",count); 69 } 70 return 0; 71 }
动规算法:(参考来源)
dp[i][j]= (dp[i-1][j]&&(a[i]==c[i+j]))||(dp[i][j-1]&&(b[j]==c[i+j]))
1 #include<stdio.h> 2 #include<string.h> 3 4 char a[201],b[201],c[402]; 5 int la,lb,lc; 6 int dp[201][201]; 7 8 int main() 9 { 10 int ncase; 11 scanf("%d",&ncase); 12 for(int n=1; n<=ncase; n++) { 13 14 a[0]=‘p‘; 15 b[0]=‘p‘; 16 c[0]=‘p‘; 17 18 scanf("%s%s%s",a+1,b+1,c+1); 19 20 la=strlen(a); 21 lb=strlen(b); 22 lc=strlen(c); 23 24 la-=1; 25 lb-=1; 26 27 //处理边界 28 for (int i=1; i<=la; i++) 29 if (a[i]==c[i]) dp[i][0]=1; 30 31 for (int i=1; i<=lb; i++) 32 if (b[i]==c[i]) dp[0][i]=1; 33 //DP 34 for (int i=1; i<=la; i++) 35 for (int j=1; j<=lb; j++) 36 dp[i][j]= (dp[i-1][j]&&(a[i]==c[i+j]))||(dp[i][j-1]&&(b[j]==c[i+j])); 37 38 printf("Data set %d: ",n); 39 if (dp[la][lb]==1) printf("yes\n"); 40 else printf("no\n"); 41 42 } 43 }
虽然代码简洁明了易理解,但是个人感觉下面的代码更准确一些。
来源:http://www.cnblogs.com/yu-chao/archive/2012/02/26/2369052.html
若用DP来作先定义res[i][j]=1表示串1前i个字符和串2的前j个字符能组成串3的前i+j个字符,res[i][j]=0则不能。
状态转移方程如下:
Res[i][j]= (third[i+j]==first[i] && res[i-1][j]==1) ||(third[i+j]==second[j]&&res[i][j-1]==1)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 char first[201],second[201],third[401]; 6 int res[201][201]; 7 int init(int n,int m) 8 { 9 int i; 10 for(i=1;i<=m;i++) 11 if(second[i]==third[i]) res[0][i]=1; 12 else break; 13 for(i=1;i<=n;i++) 14 if(first[i]==third[i]) res[i][0]=1; 15 else break; 16 return 0; 17 } 18 int dp(int n,int m) 19 { 20 int i,j; 21 for(i=1;i<=n;i++) 22 for(j=1;j<=m;j++) 23 { 24 if(third[i+j]==first[i] && res[i-1][j]) res[i][j]=1; 25 if(third[i+j]==second[j] && res[i][j-1]) res[i][j]=1; 26 } 27 if(res[n][m]) return 1; 28 return 0; 29 } 30 int main() 31 { 32 int n,len1,len2,count=0;; 33 scanf("%d",&n); 34 while(n--) 35 { 36 count++; 37 scanf("%s %s %s",first+1,second+1,third+1); 38 len1=strlen(first+1); 39 len2=strlen(second+1); 40 memset(res,0,sizeof(res)); 41 init(len1,len2); 42 43 if(dp(len1,len2)) 44 printf("Data set %d: yes\n",count); 45 else 46 printf("Data set %d: no\n",count); 47 } 48 return 0; 49 }
原文:http://www.cnblogs.com/huashanqingzhu/p/7348218.html