前言:我们队的dp一直是我在做,说不上做的很顺,有些可以做,有些不能做。到现在为止,做dp题目也有七八十道了,除了背包问题的题目我可以说有百分之七八十的把握ac的话,其他类型的dp,还真没有多大把握。越是做dp题,就越是发现dp的博大精深,我想,dp这个专题,对于我这样的人来说,做上两百道,才能真正有所把握.........

25道dp题题目:

1.hdu  1503

题意:给你两个字符串,要你用这两个字符串组成这样一个字符串,在组成的字符串中字符的相对顺序不变的情况下,可以在组成的字符串中找到原先两个字符串,字母可以错开,但是相对顺序不能变化,要这个组成的字符串中字母数最少,并输出这个字符串。

Sample Input
apple peach
ananas banana
pear peach
 
Sample Output
appleach
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 }
View Code

2、hdu 1502

题意:给你A,B,C三种字母,问你,当有n个A,n个B,n个C的时候,满足组成的字符串的所有前缀A的个数大于等于B的个数大于等于C的个数,并B的个数大于等于C的个数有多少个?

Sample Input
2
3
Sample Output
5
42
思路:这道dp题的转移方程是dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k]+dp[i][j][k-1];(i>j>k)
当然,我是用记忆化搜索+打表过的,在记忆化搜索里面写大数的加法,然后打个表,就出结果了。
打表是一种神器,不要小看它........
记忆化搜索代码:
  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 }
View Code

打表代码:

 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 }
View Code

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 }
View Code

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 }
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-21
  • 2021-08-28
  • 2021-04-17
  • 2021-11-26
  • 2022-12-23
相关资源
相似解决方案