前言:我们队的dp一直是我在做,说不上做的很顺,有些可以做,有些不能做。到现在为止,做dp题目也有七八十道了,除了背包问题的题目我可以说有百分之七八十的把握ac的话,其他类型的dp,还真没有多大把握。越是做dp题,就越是发现dp的博大精深,我想,dp这个专题,对于我这样的人来说,做上两百道,才能真正有所把握.........
25道dp题题目:
1.hdu 1503
题意:给你两个字符串,要你用这两个字符串组成这样一个字符串,在组成的字符串中字符的相对顺序不变的情况下,可以在组成的字符串中找到原先两个字符串,字母可以错开,但是相对顺序不能变化,要这个组成的字符串中字母数最少,并输出这个字符串。
ananas banana
pear peach
bananas
pearch
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int dp[1000][1000],vist[200][200]; 6 char s[1000],t[1000]; 7 void print(int x,int y) 8 { 9 if(x==0&&y==0) 10 return; 11 if(vist[x][y]==1) 12 { 13 print(x-1,y-1); 14 printf("%c",t[y-1]); 15 } 16 else if(vist[x][y]==2) 17 { 18 print(x-1,y); 19 printf("%c",s[x-1]); 20 } 21 else if(vist[x][y]==3) 22 { 23 print(x,y-1); 24 printf("%c",t[y-1]); 25 } 26 else if(vist[x][y]==0&&y==0&&x>0) 27 { 28 print(x-1,y); 29 printf("%c",s[x-1]); 30 } 31 else if(vist[x][y]==0&&x==0&&y>0) 32 { 33 print(x,y-1); 34 printf("%c",t[y-1]); 35 } 36 } 37 int main() 38 { 39 while(scanf("%s%s",s,t)>0) 40 { 41 int lens=strlen(s),lent=strlen(t); 42 for(int i=0;i<1000;i++) 43 dp[0][i]=dp[i][0]=0; 44 memset(vist,0,sizeof(vist)); 45 for(int i=1;i<=lens;i++) 46 { 47 for(int j=1;j<=lent;j++) 48 if(s[i-1]==t[j-1]) 49 { 50 dp[i][j]=dp[i-1][j-1]+1; 51 vist[i][j]=1; 52 } 53 54 else 55 { 56 int maxx=0; 57 if(dp[i][j-1]<dp[i-1][j]) 58 { 59 dp[i][j]=dp[i-1][j]; 60 vist[i][j]=2; 61 } 62 else 63 { 64 dp[i][j]=dp[i][j-1]; 65 vist[i][j]=3; 66 } 67 } 68 } 69 int i=lens,j=lent,cnt=0; 70 //printf("111\n"); 71 print(lens,lent); 72 printf("\n"); 73 } 74 return 0; 75 }
2、hdu 1502
题意:给你A,B,C三种字母,问你,当有n个A,n个B,n个C的时候,满足组成的字符串的所有前缀A的个数大于等于B的个数大于等于C的个数,并B的个数大于等于C的个数有多少个?
3
42
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int dp[62][62][62][30],n; 6 void dfs(int x,int y,int z,int w) 7 { 8 int i=0; 9 while(dp[x][y][z][i]==0) i++; 10 if(i<=20) 11 { 12 //printf("%d %d\n",dp[x1][y1][z1][20],dp[x][y][z][20]); 13 return; 14 } 15 if(x<y) return; 16 if(x<z) return; 17 if(y<z) return; 18 if(x<n) 19 { 20 dfs(x+1,y,z,1); 21 int i=0; 22 while(dp[x+1][y][z][i]==0) i++; 23 if(i<=20) 24 { 25 //printf("%d %d %d\n",x,y,z); 26 for(int j=20;j>0;j--) 27 { 28 dp[x][y][z][j]+=dp[x+1][y][z][j]; 29 if(dp[x][y][z][j]/100000>0) 30 { 31 dp[x][y][z][j-1]+=dp[x][y][z][j]/100000; 32 dp[x][y][z][j]%=100000; 33 } 34 } 35 } 36 } 37 38 if(y<n) 39 { 40 dfs(x,y+1,z,2); 41 int i=0; 42 while(dp[x][y+1][z][i]==0) i++; 43 if(i<=20) 44 { 45 //printf("%d %d %d\n",x,y,z); 46 for(int j=20;j>0;j--) 47 { 48 dp[x][y][z][j]+=dp[x][y+1][z][j]; 49 if(dp[x][y][z][j]/100000>0) 50 { 51 dp[x][y][z][j-1]+=dp[x][y][z][j]/100000; 52 dp[x][y][z][j]%=100000; 53 } 54 } 55 } 56 } 57 58 if(z<n) 59 { 60 dfs(x,y,z+1,3); 61 int i=0; 62 while(dp[x][y][z+1][i]==0) i++; 63 if(i<=20) 64 { 65 //printf("%d %d %d\n",x,y,z); 66 for(int j=20;j>0;j--) 67 { 68 dp[x][y][z][j]+=dp[x][y][z+1][j]; 69 if(dp[x][y][z][j]/100000>0) 70 { 71 dp[x][y][z][j-1]+=dp[x][y][z][j]/100000; 72 dp[x][y][z][j]%=100000; 73 } 74 } 75 } 76 } 77 78 } 79 int main() 80 { 81 //n=60; 82 //memset(dp,0,sizeof(dp)); 83 //dp[60][60][60][20]=1; 84 //dfs(0,0,0,0); 85 n=0; 86 while(scanf("%d",&n)>0) 87 { 88 int i=0; 89 memset(dp,0,sizeof(dp)); 90 dp[n][n][n][20]=1; 91 dfs(0,0,0,0); 92 while(dp[0][0][0][i]==0) i++; 93 printf("%c",'"'); 94 printf("%d",dp[0][0][0][i]); 95 i++; 96 while(i<20) 97 { 98 printf("%05d",dp[0][0][0][i]); 99 i++; 100 } 101 if(i==20) 102 { 103 printf("%05d",dp[0][0][0][i]); 104 } 105 106 printf("%c",'"'); 107 printf(","); 108 printf("\n"); 109 dp[n][n][n][20]=0; 110 n++; 111 } 112 return 0; 113 }
打表代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 char s[150][1000]={ 6 "1", 7 "1", 8 "5", 9 "42", 10 "462", 11 "6006", 12 "87516", 13 "1385670", 14 "23371634", 15 "414315330", 16 "7646001090", 17 "145862174640", 18 "2861142656400", 19 "57468093927120", 20 "1178095925505960", 21 "24584089974896430", 22 "521086299271824330", 23 "11198784501894470250", 24 "243661974372798631650", 25 "5360563436201569896300", 26 "119115896614816702500900", 27 "2670926804331443293626900", 28 "60386171228363065768956000", 29 "1375596980582110638216817680", 30 "31554078431506568639711925552", 31 "728440733705121725605657358256", 32 "16916012593818937850175820875056", 33 "394984727560107218767652172156480", 34 "9269882950945137003216002357575872", 35 "218589820552932101591964442689934272", 36 "5177405669064206309480641678873685136", 37 "123139887106265725065261170839575261246", 38 "2940211742938376804365727956142799686970", 39 "70461309651358512358741033490151564263034", 40 "1694426732092192797198296281548882854896770", 41 "40879953049935966764838175153044218787509460", 42 "989318124094680800242093703952690318964293660", 43 "24011992526103689868224096174884123328708261100", 44 "584414956558400574946623386902564355477176447080", 45 "14261150342358043298392602404780869211095488665940", 46 "348876433985002864104580005170614922408018905657020", 47 "8555006509113973886896694412506009110609925390878620", 48 "210257823823361408953856390159370731312558948560177500", 49 "5178713915261459187808923452167773648813573133021584000", 50 "127816663734641521693312994768720558317819058630953008000", 51 "3160890723051037742300958639363743464856851891194511344000", 52 "78316111638147520232116305011469771592038383559489541704000", 53 "1943917771018304520047172570820410402016667020494472553010000", 54 "48334523581589010102952513742546024844918906756931542442556400", 55 "1203813957908516875152358489329058054078745007110871474716375280", 56 "30029983483935083858438698423851117882968874317657169412268673840", 57 "750270153399794678576435057573545926324276055884108148422050727840", 58 "18772482769028405636917719941593858764528793976890630506115671775200", 59 "470373947038907707302405010980987131831213397364392909428995307126880", 60 "11802109943885320655951253002795677125946808879324767545672973160638080", 61 "296516920131524804299707608337156053506400465189952712435084509896783040", 62 "7459203321130790040650176332416188852363369960068846727881499803410725440", 63 "187875141510304732204453155491218970539216498205240765481036372897711988800", 64 "4737637890492057297860769571861620074038072983555206964113320603342642320960", 65 "119605940186192921945993199027326146131452990076639651225155962772912609414400", 66 "3022912056752362939484322031260179006906680462576858197252183463144268821651200", 67 }; 68 int main() 69 { 70 int n; 71 while(scanf("%d",&n)>0) 72 { 73 printf("%s\n\n",s[n]); 74 } 75 return 0; 76 }
3、hdu3008
题意:需要打一只boss,小明和boss都是每秒攻击一次,但是是小明先攻击boss。小明和boss的血量都是100,小明的普通攻击为1,当然除了普通攻击外,小明还有魔法攻击,小明的魔法量也是100,每次魔法攻击都需要扣除一定量的魔法值,boss的攻击力是固定的为q,小明有n种魔法技能,在小明每次攻击之后会回复t点魔法值,每种魔法技能伤害为bi,耗费魔法值为ai,然后问小明打死boss所要用的最少时间,当然如果小明不能打死boss,输出My god
思路:dp[i][j]代表着小明第i次攻击,还剩下j点魔法值的情况下打掉的boss血量,
dp[i][j]=max(dp[i-1][j-t]+1,dp[i-1][j+s[k][0]-t]+s[k][1]);
当然,这只是一个粗略的转移方程,其中的魔法值不超过100,等等细节还需处理好
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 int dp[105][105]; 7 struct node 8 { 9 int x,y; 10 }s[105]; 11 int cmp(const node a,const node b) 12 { 13 if((double)a.x/(double)a.y>(double)b.x/(double)b.y) 14 return 1; 15 else 16 return 0; 17 } 18 int main() 19 { 20 int n,p,t; 21 while(scanf("%d%d%d",&n,&p,&t)>0&&(n+p+t)) 22 { 23 for(int i=1;i<=n;i++) 24 scanf("%d%d",&s[i].x,&s[i].y); 25 //sort(s+1,s+1+n,cmp); 26 memset(dp,0,sizeof(dp)); 27 dp[0][0]=0; 28 s[0].x=0; //把普通攻击也算成一种魔法攻击 29 s[0].y=1; 30 int flag=0; 31 int tmp=100/t; //算出小明最多可以攻击的次数 32 if(100%t>0) 33 tmp++; 34 //printf("%d\n",tmp); 35 int cnt=0; 36 for(int i=1;i<=tmp;i++) 37 { 38 for(int j=0;j<=n;j++) 39 { 40 for(int k=100;k>=s[j].x;k--) 41 { 42 int ans=k-s[j].x+p; 43 if(ans>100) 44 ans=100; 45 if(dp[i-1][k]+s[j].y>dp[i][ans]) 46 dp[i][ans]=dp[i-1][k]+s[j].y; 47 // printf("%d %d %d\n",dp[i][ans],s[i].x,s[i].y); 48 if(dp[i][ans]>=100) 49 { 50 flag=1; 51 cnt=i; 52 break; 53 } 54 } 55 if(flag) 56 break; 57 } 58 if(flag) 59 break; 60 } 61 if(flag==0) 62 printf("My god\n"); 63 else 64 printf("%d\n",cnt); 65 //printf("%d\n",dp[100][i]); 66 } 67 return 0; 68 }
4、hdu1501
题意:给你三个单词,在前两个单词相对顺序不变的情况下,是否能组成第三个单词?第三个单词的长度是前两个单词的长度和
思路:普通搜索和记忆化搜索都是可以的,主要是要剪枝,判断第三个单词的最后一个字母是否由前两个单词的最后一个字母组成......
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 char s[4][500],dp[500]; 6 int len1,len2,len0,flag=0; 7 int dfs(int num0,int num1,int num2) 8 { 9 //printf("1111\n"); 10 if(dp[num2]>0) 11 return 1; 12 if(num1>=len1&&num0>=len0) 13 return 0; 14 if(num0==len0&&s[1][num1]!=s[2][num2]) 15 return 0; 16 if(num1==len1&&s[0][num0]!=s[2][num2]) 17 return 0; 18 if(s[0][num0]!=s[2][num2]&&s[1][num1]!=s[2][num2]) 19 return 0; 20 if(num0<len0&&s[0][num0]==s[2][num2]) 21 { 22 dp[num2]=dfs(num0+1,num1,num2+1); 23 } 24 if(num1<len1&&s[1][num1]==s[2][num2]) 25 { 26 dp[num2]=dfs(num0,num1+1,num2+1); 27 } 28 return dp[num2]; 29 } 30 int main() 31 { 32 int text,f=0; 33 scanf("%d",&text); 34 while(text--) 35 { 36 scanf("%s%s%s",s[0],s[1],s[2]); 37 len0=strlen(s[0]); 38 len1=strlen(s[1]); 39 len2=strlen(s[2]); 40 flag=0; 41 memset(dp,0,sizeof(dp)); 42 dp[len2]=1; 43 if(len0+len1>=len2&&(s[0][len0-1]==s[2][len2-1]||s[1][len1-1]==s[2][len2-1])) 44 flag=dfs(0,0,0); 45 printf("Data set %d: ",++f); 46 if(flag==1) 47 printf("yes\n"); 48 else 49 printf("no\n"); 50 } 51 return 0; 52 }