Now, this article is for hdu dp problems! Come on !
hdu 2391 Filthy Rich Problem link adress:http://acm.hdu.edu.cn/showproblem.php?pid=2391
This problem is silimar to one of the problem in the province contest,so cleared it successfully!
In a world, it's a good problem!
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 int t; 7 int n,m; 8 int map[1005][1005]; 9 int ans[1005][1005]; 10 int max(int a,int b,int c) 11 { 12 int big; 13 big=a>b?a:b; 14 big=c>big?c:big; 15 return big; 16 } 17 int main() 18 { 19 int flag=1; 20 cin>>t; 21 while(t--) 22 { 23 cin>>n>>m; 24 int i,j; 25 memset(map,0,sizeof(map)); 26 memset(ans,0,sizeof(ans)); 27 for(i=1;i<=n;i++) 28 for(j=1;j<=m;j++) 29 cin>>map[i][j]; 30 for(i=2;i<=n+1;i++) 31 for(j=2;j<=m+2;j++) 32 { 33 ans[i][j]=max(ans[i-1][j]+map[i-1][j-1],ans[i][j-1]+map[i-1][j-1],ans[i-1][j-1]+map[i-1][j-1]); 34 } 35 36 printf("Scenario #%d:\n",flag++); 37 cout<<ans[n+1][m+1]<<endl<<endl; 38 } 39 return 0; 40 } 41
hdu 4508 (完全背包) 湫湫系列故事 减肥记I http://acm.hdu.edu.cn/showproblem.php?pid=4508
多重背包问题,N久没有刷背包题了,比赛时,居然把它当做贪心猛做了好久!泪奔啊!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define N 105 6 int n; 7 int x[N],y[N]; 8 int dp[100005]; 9 int len; 10 int main() 11 { 12 int i,j; 13 while(scanf("%d",&n)!=EOF) 14 { 15 memset(x,0,sizeof(x)); 16 memset(y,0,sizeof(y)); 17 for(i=0;i<n;i++) 18 scanf("%d%d",&x[i],&y[i]); 19 scanf("%d",&len); 20 memset(dp,0,sizeof(dp)); 21 for(i=0;i<n;i++) 22 for(j=0;j<=len;j++) 23 { 24 if(j<y[i]) continue;//这一点很重要啊 25 if(dp[j]<dp[j-y[i]]+x[i]) 26 dp[j]=dp[j-y[i]]+x[i]; 27 } 28 printf("%d\n",dp[len]); 29 } 30 return 0; 31 }
hdu 4502 (dp) 吉哥系列故事--临时工计划 http://acm.hdu.edu.cn/showproblem.php?pid=4502
这一题有必要做个详细的分析了;
Problem Description
俗话说一分钱难倒英雄汉,高中几年下来,吉哥已经深深明白了这个道理,因此,新年开始存储一年的个人资金已经成了习惯,不过自从大学之后他不好意思再向大人要压岁钱了,只能把唯一的希望放到自己身上。可是由于时间段的特殊性和自己能力的因素,只能找到些零零碎碎的工作,吉哥想知道怎么安排自己的假期才能获得最多的工资。
已知吉哥一共有m天的假期,每天的编号从1到m,一共有n份可以做的工作,每份工作都知道起始时间s,终止时间e和对应的工资c,每份工作的起始和终止时间以天为单位(即天数编号),每份工作必须从起始时间做到终止时间才能得到总工资c,且不能存在时间重叠的工作。比如,第1天起始第2天结束的工作不能和第2天起始,第4天结束的工作一起被选定,因为第2天吉哥只能在一个地方工作。
现在,吉哥想知道怎么安排才能在假期的m天内获得最大的工资数(第m+1天吉哥必须返回学校,m天以后起始或终止的工作是不能完成的)。
Input
第一行是数据的组数T;每组数据的第一行是2个正整数:假期时间m和可做的工作数n;接下来n行分别有3个正整数描述对应的n个工作的起始时间s,终止时间e,总工资c。
[Technical Specification]
1<=T<=1000
9<m<=100
0<n<=1000
s<=100, e<=100, s<=e
c<=10000
Output
对于每组数据,输出吉哥可获得的最高工资数。
Sample Input
1
10 5
1 5 100
3 10 10
5 10 100
1 4 2
6 12 266
这个问题用贪心做了很久,发现行不通,估计需要用动态规划!但是这题递归方程不是很好想!
循环方程仍分为两层,第一层循环工作,第二层循环时间;(对于每一个工作都记录从1-m天的结果)
那么对第i个工作来说,如果当前的天数j满足j小于工作i的结束时间,那么他将得不到工作i的工资,所以有:dp[i][j]=dp[i-1][j];
如果满足dp[i-1][s[i].s-1]+s[i].p>dp[i-1][j];如果当前工作i所得的工资加上dp[i-1][s[i].s-1]的和大于dp[i-1][j],那么就更新,否则仍有dp[i][j]=dp[i-1][j]!
最后所得的dp[n][m]即为所求的值!
ps: DP是一个动态的记录最有answer的表格,在这个表格中,当前的循环总要借助于上一层的成果,层层递进,知道最后的最终解出现!
下面的代码中加入了结果显示,更好的显示了dp的特性!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int t; 7 int m,n; 8 int dp[1005][105]; 9 struct node{ 10 int s,e,p; 11 }s[1005]; 12 bool cmp(node a,node b) 13 { 14 return a.s<b.s; 15 } 16 int main() 17 { 18 int i,j; 19 scanf("%d",&t); 20 while(t--) 21 { 22 scanf("%d%d",&m,&n); 23 for(i=1;i<=n;i++) 24 scanf("%d%d%d",&s[i].s,&s[i].e,&s[i].p); 25 26 printf("\n"); 27 28 sort(s+1,s+n+1,cmp); 29 //显示排序结果 30 for(i=1;i<=n;i++) 31 printf("%d %d %d\n",s[i].s,s[i].e,s[i].p); 32 printf("\n"); 33 34 memset(dp,0,sizeof(dp)); 35 for(j=0;j<=m;j++) 36 { 37 if(j<s[1].e) 38 dp[1][j]=0; 39 else 40 dp[1][j]=s[1].p; 41 } 42 for(i=2;i<=n;i++) 43 for(j=1;j<=m;j++) 44 { 45 if(s[i].e>j) 46 dp[i][j]=dp[i-1][j]; 47 else if(dp[i-1][s[i].s-1]+s[i].p>dp[i-1][j]) 48 dp[i][j]=dp[i-1][s[i].s-1]+s[i].p; 49 else 50 dp[i][j]=dp[i-1][j]; 51 } 52 //显示dp后的结果 53 for(i=1;i<=n;i++) 54 { 55 for(j=1;j<=m;j++) 56 printf("%d ",dp[i][j]); 57 printf("\n"); 58 } 59 60 printf("\n"); 61 62 printf("%d\n",dp[n][m]); 63 } 64 return 0; 65 }
post by heat_nan@ 2013-03-23 14:51
DP去年草草学了两天就没管了,当时好像很难理解,大部分题都是囫囵吞枣!现在有必要好好复习一下,加深边理解了!
hdu 1003 Max Sum http://acm.hdu.edu.cn/showproblem.php?pid=1003
给定一串数字,计算最大的连续和,输出该最大子串的最大值和起始位置.
思路:设sum为当前状态的最大值,max为整个过程连续字串的最大值,转移状态方程:
如果sum+num[i]大于max,则更新max和起始位置的值,如果小于或者等于,不做处理,若果sum的当前值小于0时,那么需要令sum=0,重新定义开始的位置开始统计。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int t; 6 int n; 7 int num[100005]; 8 int main() 9 { 10 int i; 11 scanf("%d",&t); 12 int c=1; 13 while(t--) 14 { 15 scanf("%d",&n); 16 memset(num,0,sizeof(num)); 17 int b,e; 18 for(i=0;i<n;i++) 19 scanf("%d",&num[i]); 20 int sum=0; 21 int max=-9999; 22 int flag=1; 23 for(i=0;i<n;i++) 24 { 25 sum+=num[i]; 26 if(sum>max) 27 { 28 max=sum; 29 b=flag; 30 e=i+1; 31 } 32 if(sum<0) 33 { 34 sum=0; 35 flag=i+2; 36 37 } 38 39 } 40 printf("Case %d:\n%d %d %d\n",c++,max,b,e); 41 if(t!=0) printf("\n"); 42 } 43 return 0; 44 } 45
hdu 2602 bone collector http://acm.hdu.edu.cn/showproblem.php?pid=2602
经典赤裸裸的01背包问题,模板!
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 int dp[1005]; 6 int a[1005],b[1005]; 7 int n,v; 8 int t; 9 int max(int a,int b) 10 { 11 return a>b?a:b; 12 } 13 int main() 14 { 15 int i,j; 16 scanf("%d",&t); 17 while(t--) 18 { 19 scanf("%d%d",&n,&v); 20 memset(a,0,sizeof(a)); 21 memset(b,0,sizeof(b)); 22 memset(dp,0,sizeof(dp)); 23 for(i=0;i<n;i++) 24 scanf("%d",&a[i]); 25 for(j=0;j<n;j++) 26 scanf("%d",&b[j]); 27 for(i=0;i<n;i++) 28 { 29 for(j=v;j>=b[i];j--) 30 { 31 dp[j]=max(dp[j],dp[j-b[i]]+a[i]); 32 } 33 } 34 // for(i=1;i<=v;i++) 35 // printf("%d ",dp[i]); 36 printf("%d\n",dp[v]); 37 38 } 39 return 0; 40 }
hdu 2084 dp经典数塔 http://acm.hdu.edu.cn/showproblem.php?pid=2084
学习dp做的第一题!经典!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int t; 6 int h; 7 int map[105][105]; 8 int dp[105][105]; 9 int max(int a,int b) 10 { 11 return a>b?a:b; 12 } 13 int main() 14 { 15 int i,j; 16 scanf("%d",&t); 17 while(t--) 18 { 19 scanf("%d",&h); 20 for(i=0;i<h;i++) 21 for(j=0;j<=i;j++) 22 scanf("%d",&map[i][j]); 23 memset(dp,0,sizeof(dp)); 24 for(i=h-1;i>=0;i--) 25 for(j=0;j<=i;j++) 26 { 27 dp[i][j]=max(dp[i+1][j]+map[i][j],dp[i+1][j+1]+map[i][j]); 28 } 29 30 //for(i=0;i<h;i++) 31 //{ 32 // for(j=0;j<=i;j++) 33 // printf("%d ",dp[i][j]); 34 // printf("\n"); 35 //} 36 37 38 printf("%d\n",dp[0][0]); 39 } 40 return 0; 41 }
hdu 1711 Big Event in HDU http://acm.hdu.edu.cn/showproblem.php?pid=1171 背包
有t种物品,每种物品n个,价值为v,把这些东西分为两部分,要求两部分的价值尽可能相等,如果无法保证相等,一部分的值不能小于另一部分。
详细分析: http://www.cnblogs.com/heat-man/archive/2013/03/02/2940391.html
唯一不知道就是为什么注释掉的那种输出方式是错误的。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 #define N 250000 7 #define M 55 8 int dp[N]; 9 int n[M],v[M]; 10 int max(int a,int b) 11 { 12 if(a>b) 13 return a; 14 else 15 return b; 16 } 17 int main() 18 { 19 20 int t; 21 while(cin>>t) 22 { 23 if(t<0) break; 24 memset(n,0,sizeof(n)); 25 memset(v,0,sizeof(v)); 26 int i,j,k; 27 int sum=0; 28 for(i=0;i<t;i++) 29 { 30 31 cin>>v[i]>>n[i]; 32 sum+=v[i]*n[i]; 33 } 34 int all=sum; 35 sum/=2; 36 memset(dp,0,sizeof(dp)); 37 for(i=0;i<t;i++) 38 for(j=1;j<=n[i];j++) 39 for(k=sum;k>=v[i];k--) 40 { 41 dp[k]=max(dp[k-v[i]]+v[i],dp[k]); 42 } 43 // if(dp[sum]>=sum) 44 // cout<<dp[sum]<<" "<<all-dp[sum]<<endl; 45 // else 46 // cout<<all-dp[sum]<<" "<<dp[sum]<<endl; 47 int rest=all-dp[sum]; 48 if(dp[sum]<rest) 49 swap(dp[sum],rest); 50 cout<<dp[sum]<<" "<<rest<<endl; 51 52 } 53 return 0; 54 }