hdu26道动态规划总结
前言:我们队的dp一直是我在做,说不上做的很顺,有些可以做,有些不能做。到现在为止,做dp题目也有七八十道了,除了背包问题的题目我可以说有百分之七八十的把握ac的话,其他类型的dp,还真没有多大把握。越是做dp题,就越是发现dp的博大精深,我想,dp这个专题,对于我这样的人来说,做上两百道,才能真正有所把握.........
25道dp题题目:
1.hdu 1503
题意:给你两个字符串,要你用这两个字符串组成这样一个字符串,在组成的字符串中字符的相对顺序不变的情况下,可以在组成的字符串中找到原先两个字符串,字母可以错开,但是相对顺序不能变化,要这个组成的字符串中字母数最少,并输出这个字符串。
ananas banana
pear peach
bananas
pearch
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
打表代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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,等等细节还需处理好
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
题意:给你三个单词,在前两个单词相对顺序不变的情况下,是否能组成第三个单词?第三个单词的长度是前两个单词的长度和
思路:普通搜索和记忆化搜索都是可以的,主要是要剪枝,判断第三个单词的最后一个字母是否由前两个单词的最后一个字母组成......
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
5、hdu1300
题意:有n种珠宝,每种珠宝有其等级,现在按照珠宝的等级从低到高给出,每种珠宝需要买的数量,以及珠宝的价格。每买一种珠宝,就必须多买额外10串这种珠宝,当然可以买高等级的珠宝来代替低等级的,这样就只需额外的买10串高等级的珠宝,求最少的价值。
思路:由于已经按照等级排好序,那么dp[i]代表买i种等级的珠宝所用的最少价值。那么dp[i]=min{dp[i-1]+(s[i][0]+10)*s[i][1],dp[j]+(sum[i]-sum[j]+10)*s[i][1]}(1<=k<i)
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int dp[100000],t[7],s[100000][2],cont[100000]; 6 int main() 7 { 8 int text; 9 scanf("%d",&text); 10 while(text--) 11 { 12 int n; 13 scanf("%d",&n); 14 cont[0]=0; 15 for(int i=1;i<=n;i++) 16 { 17 scanf("%d%d",&s[i][0],&s[i][1]); 18 cont[i]=cont[i-1]+s[i][0]; 19 } 20 dp[0]=0; 21 for(int i=1;i<=n;i++) 22 { 23 dp[i]=dp[i-1]+(s[i][0]+10)*s[i][1]; 24 int minx=100000000; 25 for(int j=0;j<i;j++) 26 { 27 int tmp=dp[j]+(cont[i]-cont[j]+10)*s[i][1]; 28 if(tmp<minx) 29 minx=tmp; 30 } 31 if(dp[i]>minx) 32 dp[i]=minx; 33 } 34 printf("%d\n",dp[n]); 35 } 36 return 0; 37 }
6、hdu1422(水题)
7、hdu1224
题意:给你n+1个点,其中1是起点,同时n+1是终点,终点和起点是同一个点,飞机只能从编号小的点飞到编号大的点,每个编号都有愉快值,求能从起点飞到终点的最大愉快值。
思路:dp[i]=max(dp[j])+s[i];(j<i)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<queue> 5 using namespace std; 6 int dp[200],vist[200][200],a[200],path[200],n; 7 void print(int num) 8 { 9 if(num==0) 10 return; 11 if(path[num]!=0) 12 { 13 print(path[num]); 14 } 15 if(num!=n+1) 16 printf("%d->",num); 17 } 18 int main() 19 { 20 int text,p=0; 21 scanf("%d",&text); 22 while(text--) 23 { 24 //int n; 25 scanf("%d",&n); 26 memset(a,0,sizeof(a)); 27 for(int i=1;i<=n;i++) 28 scanf("%d",&a[i]); 29 int m; 30 scanf("%d",&m); 31 memset(vist,0,sizeof(vist)); 32 memset(dp,0,sizeof(dp)); 33 dp[1]=1; 34 for(int i=1;i<=m;i++) 35 { 36 int tmp1,tmp2; 37 scanf("%d%d",&tmp1,&tmp2); 38 if(tmp1>tmp2) 39 swap(tmp1,tmp2); 40 vist[tmp1][tmp2]=1; 41 } 42 memset(path,0,sizeof(path)); 43 int maxn=1,k=-1; 44 for(int i=2;i<=n+1;i++) 45 { 46 int maxp=-10000; 47 for(int j=1;j<i;j++) 48 { 49 if(dp[j]!=0&&vist[j][i]!=0&&maxp<dp[j]) 50 { 51 maxp=dp[j]; 52 path[i]=j; 53 } 54 } 55 if(maxp>dp[i]) 56 dp[i]=maxp+a[i]; 57 if(dp[i]>maxn) 58 { 59 maxn=dp[i]; 60 k=i; 61 } 62 } 63 printf("CASE %d#\n",++p); 64 65 printf("points : %d\n",dp[n+1]-1); 66 67 printf("circuit : "); 68 69 print(n+1); 70 printf("1\n"); 71 if(text) 72 printf("\n"); 73 } 74 return 0; 75 }
8、hdu1074
这是道状态压缩dp,我打算放在状态压缩dp里面再详细说说
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 struct node 6 { 7 int pre; 8 int cost; 9 int num; 10 }dp[42767]; 11 struct node1 12 { 13 char name[205]; 14 int cost; 15 int qx; 16 }s[20]; 17 bool vist[50000]; 18 void print(int x) 19 { 20 int tmp=x,k=0; 21 tmp=x^dp[x].pre; 22 tmp=tmp>>1; 23 //printf("%d\n",tmp); 24 while(tmp) 25 { 26 k++; 27 tmp=tmp>>1; 28 //printf("%d\n",tmp); 29 } 30 if(dp[x].pre!=0) 31 { 32 print(dp[x].pre); 33 } 34 printf("%s\n",s[k].name); 35 } 36 int main() 37 { 38 int text; 39 scanf("%d",&text); 40 while(text--) 41 { 42 int n; 43 scanf("%d",&n); 44 for(int i=0;i<n;i++) 45 scanf("%s%d%d",s[i].name,&s[i].qx,&s[i].cost); 46 int m=1<<n; 47 dp[0].pre=-1; 48 dp[0].cost=0; 49 dp[0].num=0; 50 memset(vist,false,sizeof(vist)); 51 vist[0]=true; 52 for(int i=0;i<m-1;i++) 53 { 54 for(int j=0;j<n;j++) 55 { 56 int tmp=1<<j; 57 if((tmp&i)==0) 58 { 59 int tmp1=tmp|i; 60 dp[tmp1].cost=dp[i].cost+s[j].cost; 61 int r=dp[tmp1].cost-s[j].qx; 62 if(r<0) 63 r=0; 64 r=r+dp[i].num; 65 if(!vist[tmp1]) 66 { 67 vist[tmp1]=true; 68 dp[tmp1].num=r; 69 dp[tmp1].pre=i; 70 } 71 else if(dp[tmp1].num>r) 72 { 73 dp[tmp1].num=r; 74 dp[tmp1].pre=i; 75 } 76 } 77 } 78 } 79 printf("%d\n",dp[m-1].num); 80 print(m-1); 81 } 82 return 0; 83 }
9、hdu1080(带权值的最长公共子序列问题)
题意:给你两串字符,要你求这两字符的最大匹配值。每个字符与其他字符匹配,都有一个权值,权值表已经给出,输入输出中,只有这么几种字符,可以用空格代替字符。
思路:变形的最长公共子序列。
反思:我以前一直认为最长公共子序列就是哥模板,顶多再来个记录路径,没有想到,这次是它的变形。其实做题目,最好的就是做变形题,这样可以开拓自己的思路......
在最长公共子序列中,dp[i][j]代表的是字符串s前i-1个字符与字符串t钱j-1个字符的最大匹配数,所以,当s[i-1]与t[i-1]匹配的时候,取dp[i-1][j-1]+1;当s[i-1]与
t[j-1]不匹配的时候,我们取dp[i-1][j],dp[i][j-1]的最大值,dp[i-1][j]代表着s串中长度为i-2的字符与t串中长度为j-1的字符匹配的最大长度。
如此,这个题目带权值,那么
dp[i][j]代表的是,字符串s前i-1个字符与字符串t钱j-1个字符匹配的最大权值,那么当我们让s[i-1]与t[j-1]匹配的时候(这两个字符不一定要相等,只是需要匹配的权值),可以匹配上的话,dp[i][j]=dp[i-1][j-1]+匹配上的权值;
若是不能匹配的话,dp[i][j]有两种情况,dp[i][j]=dp[i-1][j]+s串中第i-1个字符与t串中空格所匹配的权值........下面那个也是同理
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define M -1000000000 6 int dp[200][200]; 7 char s[200],t[200]; 8 int find(char ch) 9 { 10 if(ch=='A') 11 return 0; 12 if(ch=='C') 13 return 1; 14 if(ch=='G') 15 return 2; 16 if(ch=='T') 17 return 3; 18 if(ch=='-') 19 return 4; 20 } 21 int main() 22 { 23 int text; 24 scanf("%d",&text); 25 int a[5][5]={ 26 5,-1,-2,-1,-3, 27 -1,5,-3,-2,-4, 28 -2,-3,5,-2,-2, 29 -1,-2,-2,5,-1, 30 -3,-4,-2,-1,M, 31 }; 32 while(text--) 33 { 34 int lens,lent; 35 scanf("%d %s",&lens,s); 36 scanf("%d %s",&lent,t); 37 dp[0][0]=0; 38 for(int i=1;i<=lens;i++) 39 dp[i][0]=a[find(s[i-1])][find('-')]+dp[i-1][0]; 40 for(int i=1;i<=lent;i++) 41 dp[0][i]=a[find('-')][find(t[i-1])]+dp[0][i-1]; 42 for(int i=1;i<=lens;i++) 43 { 44 for(int j=1;j<=lent;j++) 45 { 46 dp[i][j]=dp[i-1][j-1]+a[find(s[i-1])][find(t[j-1])]; 47 dp[i][j]=max(dp[i][j],dp[i][j-1]+a[find('-')][find(t[j-1])]); 48 dp[i][j]=max(dp[i][j],dp[i-1][j]+a[find(s[i-1])][find('-')]); 49 } 50 } 51 printf("%d\n",dp[lens][lent]); 52 } 53 return 0; 54 }
10、hdu1059(背包问题,在背包总结有详细解答)
11、hdu1158
题意:经理有三种操作,雇佣一个人,支付它工资,开除一个人,这三种操作的花费分别为a,b,c,然后每个月经理需要si个人做事,问n个月后,经理的最小花费。
思路:dp[i][j]代表第i天有j个人时的最小花费。
dp[i][j]=min(dp[i-1][k]+abs(j-k)*(a (or) c)+j*b)(s[i-1]<=k<=maxn);其中,maxn为要雇佣的最大人数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int dp[13][10100],s[13]; 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n)>0&&n) 10 { 11 int a,b,c,maxn=0; 12 scanf("%d%d%d",&a,&b,&c); 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%d",&s[i]); 16 if(maxn<s[i]) 17 maxn=s[i]; 18 } 19 for(int i=1;i<=maxn;i++) //第一天的花费是可以确定的 20 dp[1][i]=i*(a+b); 21 for(int i=2;i<=n;i++) 22 { 23 for(int j=s[i];j<=maxn;j++) 24 { 25 dp[i][j]=1<<30; //赋值为最大 26 for(int k=s[i-1];k<=maxn;k++) 27 { 28 int cost; 29 if(k<j) 30 cost=j*b+(j-k)*a; 31 else 32 cost=j*b+(k-j)*c; 33 dp[i][j]=min(dp[i][j],dp[i-1][k]+cost); 34 } 35 } 36 } 37 int minx=dp[n][maxn]; 38 for(int i=s[n];i<=maxn;i++) 39 if(minx>dp[n][i]) 40 minx=dp[n][i]; 41 printf("%d\n",minx); 42 } 43 return 0; 44 }
12、hdu2059(水)
13、hdu1081(最长递增子序列变形)
题意:给你一些带权值的点组成的矩形,要你在这个矩形内找一个子矩形,使得这个子矩形内的点加起来权值最大......
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
思路:这其实就是一个二维的最长递增子序列......我们只需要把二维压缩成以为就好......
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int s[200][200],t[200]; 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n)>0) 10 { 11 for(int i=1;i<=n;i++) 12 { 13 for(int j=1;j<=n;j++) 14 scanf("%d",&s[i][j]); 15 } 16 int maxx=-100000000,sum; 17 for(int i=1;i<=n;i++) 18 { 19 memset(t,0,sizeof(t)); 20 for(int j=i;j<=n;j++) 21 { 22 for(int k=1;k<=n;k++) 23 { 24 t[k]+=s[j][k]; 25 } 26 sum=0; 27 for(int p=1;p<=n;p++) 28 { 29 sum+=t[p]; 30 if(sum<0) 31 sum=0; 32 if(sum>maxx) 33 maxx=sum; 34 } 35 if(maxx<sum) 36 maxx=sum; 37 } 38 } 39 printf("%d\n",maxx); 40 } 41 return 0; 42 }
14、hdu1078(水)
解题报告:http://www.cnblogs.com/ziyi--caolu/p/3197714.html
15、hdu1025(最长递增子序列模板?.....忘了,反正比较水)
代码O(nlongn):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 struct node 7 { 8 int a,b; 9 }s[500005]; 10 int cmp(const node p,const node q) 11 { 12 if(p.a<q.a) 13 return 1; 14 else if(p.a==q.a&&p.b<q.b) 15 return 1; 16 else 17 return 0; 18 } 19 int dp[500005]; 20 int main() 21 { 22 int n; 23 int text=0; 24 //scanf("%d",&text); 25 while(scanf("%d",&n)>0) 26 { 27 28 for(int i=0;i<n;i++) 29 scanf("%d%d",&s[i].a,&s[i].b); 30 sort(s,s+n,cmp); 31 dp[0]=s[0].b; 32 int len=1; 33 for(int i=1;i<n;i++) 34 { 35 int left=0,right=len-1,mid; 36 if(dp[len-1]<s[i].b) 37 dp[len++]=s[i].b; 38 else 39 { 40 right=len-1; 41 while(left<=right) 42 { 43 mid=(left+right)/2; 44 if(dp[mid]<s[i].b) 45 left=mid+1; 46 else right=mid-1; 47 } 48 dp[left]=s[i].b; 49 } 50 } 51 printf("Case %d:\n",++text); 52 if(len==1) 53 printf("My king, at most %d road can be built.\n\n",len); 54 else 55 printf("My king, at most %d roads can be built.\n\n",len); 56 } 57 return 0; 58 }
16、hdu1160(赤裸裸的最长递增子序列,模板题)
17、hdu1024(很明显的最大m字段和问题)
题意:给你一个m,一个n,后面跟n个数,要你把这n个数分成m段,m段加起来的和最大.....求最大和
思路:这个题目应当算作区间dp的,只是看到了,就将它ac了吧。dp[i][j]表示将前i个数分为j段的最大和
那么dp[i][j]=max{dp[i-1][j]+a[i],max(dp[k][j-1])+a[i]}其中k>=1,k<i;
再开一个数组来记录max(dp[k][j-1])就ok.......当然,这个题目还需要将二维压缩成一维.....
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 typedef __int64 ss; 6 #define minx -100000000 7 ss dp[1000005],f[1000005],a[1000005]; 8 int main() 9 { 10 ss n,m; 11 while(scanf("%I64d%I64d",&m,&n)>0) 12 { 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%I64d",&a[i]); 16 dp[i]=f[i]=0; 17 } 18 dp[0]=f[0]=0; 19 ss maxn; 20 for(int i=1;i<=m;i++) 21 { 22 maxn=minx; 23 for(int j=i;j<=n;j++) 24 { 25 dp[j]=max(dp[j-1],f[j-1])+a[j]; 26 f[j-1]=maxn; 27 if(maxn<dp[j]) 28 maxn=dp[j]; 29 } 30 } 31 printf("%I64d\n",maxn); 32 } 33 return 0; 34 }
18、hdu1114(背包水题)
19、hdu2191(背包水题)
20、hdu1978(记忆化搜索水题)
21、hdu1789(贪心)
22、hdu1058(经典dp)
题意:
Write a program to find and print the nth element in this sequence
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 using namespace std; 3 typedef __int64 ss; 4 int min(int x,int y,int j,int k) 5 { 6 int min1,min2; 7 if(x>y) 8 min1=y; 9 else 10 min1=x; 11 if(j>k) 12 min2=k; 13 else 14 min2=j; 15 return (min1>min2? min2:min1); 16 } 17 int main() 18 { 19 ss dp[6000],j,m,n,k,i; 20 dp[1]=1; 21 j=m=n=k=1; 22 i=2; 23 while(i<5843) 24 { 25 dp[i]=min(dp[j]*2,dp[m]*3,dp[n]*5,dp[k]*7); 26 if(dp[i]==dp[j]*2) 27 j++; 28 if(dp[i]==dp[m]*3) 29 m++; 30 if(dp[i]==dp[n]*5) 31 n++; 32 if(dp[i]==dp[k]*7) 33 k++; 34 i++; 35 } 36 while(scanf("%I64d",&n)>0&&n) 37 { 38 ss r=n%10; 39 ss f=n%100; 40 if(r==1&&f!=11) 41 printf("The %I64dst humble number is %I64d.\n",n,dp[n]); 42 else if(r==2&&f!=12) 43 printf("The %I64dnd humble number is %I64d.\n",n,dp[n]); 44 else if(r==3&&f!=13) 45 printf("The %I64drd humble number is %I64d.\n",n,dp[n]); 46 else 47 printf("The %I64dth humble number is %I64d.\n",n,dp[n]); 48 } 49 return 0; 50 }
23、hdu1421
题意:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 int dp[2005][2000],a[2005]; 7 int main() 8 { 9 int n,k; 10 while(scanf("%d%d",&n,&k)>0) 11 { 12 for(int i=1;i<=n;i++) 13 scanf("%d",&a[i]); 14 sort(a+1,a+1+n); 15 for(int i=1;i<=n;i++) 16 for(int j=1;j<=k;j++) 17 dp[i][j]=1000000000; 18 for(int i=1;i<=n;i++) 19 dp[i][0]=0; 20 for(int i=2;i<=n;i++) 21 { 22 for(int j=1;j<=i/2&&j<=k;j++) 23 dp[i][j]=min(dp[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]),dp[i-1][j]); 24 } 25 printf("%d\n",dp[n][k]); 26 } 27 return 0; 28 }
24、hdu1159(最长公共子序列模板题)
25、hdu1257(贪心或最长递增子序列)
26、hdu1244
题意:
a1 a2 a3 ... an
求按先后次序在其中取m段长度分别为l1、l2、l3...lm的不交叠的连续整数的和的最大值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int dp[1005][25],a[1005],sum[1005],s[25]; 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n)>0&&n) 10 { 11 int m; 12 scanf("%d",&m); 13 for(int i=1;i<=m;i++) 14 scanf("%d",&s[i]); 15 memset(dp,0,sizeof(dp)); 16 sum[0]=0; 17 for(int i=1;i<=n;i++) 18 { 19 scanf("%d",&a[i]); 20 sum[i]=sum[i-1]+a[i]; 21 } 22 int ans=0; 23 for(int j=1;j<=m;j++) 24 { 25 ans+=s[j]; 26 for(int i=ans;i<=n;i++) 27 { 28 dp[i][j]=max(dp[i-1][j],dp[i-s[j]][j-1]+sum[i]-sum[i-s[j]]); 29 } 30 } 31 printf("%d\n",dp[n][m]); 32 } 33 return 0; 34 }