7.8.实验 解题参考
来源:互联网 发布:usb虚拟打印机端口 编辑:程序博客网 时间:2024/06/10 01:37
ProblemA(HDU2084)
这题题目都说了经典DP
由上往下推,由于结果状态多,不好处理。无疑由底往上推比较方便,都归于一个起点,只需要算出由底往上得到的最大价值即可。
方程:dp[i][j] = max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int a[105][105],dp[105][105];int main(){ int t,n,i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(dp,0,sizeof(dp)); for(i = 1;i<=n;i++) { for(j = 1;j<=i;j++) scanf("%d",&a[i][j]); } for(i = n;i>=1;i--) { for(j = 1;j<=i;j++) { dp[i][j] = max(dp[i+1][j],dp[i+1][j+1])+a[i][j]; } } printf("%d\n",dp[1][1]); } return 0;}
ProblemB(HDU2602)
这是非常典型的01背包问题。
dp[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
状态转移方程:dp[i][v]=max{dp[i-1][v],dp[i-1][v-cost[i]]+value[i]}
这里提醒注意体积为零的情况,如:
1
5 0
2 4 1 5 1
0 0 1 0 0
结果为12
#include<iostream>using namespace std;int dp[1000][1000];int max(int x,int y){ return x>y?x:y;}int main(){ int t,n,v,i,j; int va[1000],vo[1000]; cin>>t; while(t--) { cin>>n>>v; for(i=1;i<=n;i++) cin>>va[i]; for(i=1;i<=n;i++) cin>>vo[i]; memset(dp,0,sizeof(dp));//初始化操作 for(i=1;i<=n;i++) { for(j=0;j<=v;j++) { if(vo[i]<=j)//表示第i个物品将放入大小为j的背包中 dp[i][j]=max(dp[i-1][j],dp[i-1][j-vo[i]]+va[i]);//第i个物品放入后,那么前i-1个物品可能会放入也可能因为剩余空间不够无法放入 else //第i个物品无法放入 dp[i][j]=dp[i-1][j]; } } cout<<dp[n][v]<<endl; } return 0;}
当然01背包是可以优化成一维的。
dp[i][v]是由dp[i-1][v]和dp[i-1][v-c[i]]两个子问题递推而来,完全可以对i降维。但一定要注意,必须在每次主循环中以v=V..0的顺序推dp[v],这样才能保证推dp[v]时dp[v-c[i]]保存的是状态dp[i-1][v-c[i]]的值,而没有被覆盖。了解过背包系列算法的应该知道,如果倒过来(0..V)会对每个物品产生叠加,造成重复放置,这正好是解决完全背包(物品数量无限)的算法。
#include<iostream>using namespace std;#define Size 1111int va[Size],vo[Size];int dp[Size];int Max(int x,int y){ return x>y?x:y;}int main(){ int t,n,v; int i,j; cin>>t; while(t--) { cin>>n>>v; for(i=1;i<=n;i++) cin>>va[i]; for(i=1;i<=n;i++) cin>>vo[i]; memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) { for(j=v;j>=vo[i];j--) { dp[j]=Max(dp[j],dp[j-vo[i]]+va[i]); } } cout<<dp[v]<<endl; } return 0;}
ProblemC(HDU1003)
很简单的一维DP,状态转移方程为f[i]=max(f[i-1]+a[i],a[i])
最后扫一遍找最优解。
由于需要位置,很明显最后扫一遍找最优解的时候,找到的那位即为末位置,那么只要在递推的时候顺便记录一下起始位置即可:若a[i]>f[i-1]+a[i],说明要更新,pos[i]=i;否则起始位置不变直接向后加,pos[i]=pos[i-1]。
#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;int f[100010],a[100010],pos[100010];int main(){ int T,t,n; scanf("%d",&T);t=0; while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); f[0]=a[0];pos[0]=0; for(int i=1;i<n;i++) if(f[i-1]+a[i]>=a[i]) { f[i]=f[i-1]+a[i]; pos[i]=pos[i-1]; } else { f[i]=a[i]; pos[i]=i; } int j=0; for(int i=1;i<n;i++) if(f[i]>f[j]) j=i; t++;printf("Case %d:\n",t); printf("%d %d %d\n",f[j],pos[j]+1,j+1); if(T>0) printf("\n"); } return 0;}
当然这个题其实可以一边做一边找最大值,那么再简化一下其实可以不用数组记录,就变成了用几个变量遍历过去保存最优解的方法。这是由DP进一步抽象过来的,但由于看起来已经不像DP的模式了,这里就不写这种方法咯~
ProblemD(POJ2533)
又是一种非常经典的DP类型,很多题目都可以抽象到这个原型——最长上升子序列。当前点上升序列的长度,可由其前面比它值小的点加一得到,那么最大的长度即比较前面所有能与它连起来的情况。
转移方程:f[i]=max{f[j]}+1; ( 0 <= j < i && a[j] < a[i] )
初值f[i]=1。
#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;int f[100010],a[100010];int main(){ int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); f[i]=1; } for(int i=1;i<n;i++) for(int j=0;j<i;j++) if(a[j]<a[i] && f[j]+1>f[i]) f[i]=f[j]+1; int ans=0; for(int i=0;i<n;i++) if(f[i]>ans) ans=f[i]; printf("%d\n",ans); return 0;}
- 7.8.实验 解题参考
- 7.5.实验 解题参考
- 7.6.实验 解题参考
- 7.7.实验 解题参考
- 7.11.实验 解题参考
- 7.13.实验 解题参考
- 7.14.实验 解题参考
- 实验七参考命令
- leetcode日志:解题参考引用
- x264参考帧实验讨论
- x264参考帧实验讨论:
- [Java] 实验2参考代码
- [Java] 实验3参考代码
- [Java] 实验4参考代码
- [Java] 实验5参考代码
- [Java] 实验6参考代码
- [Java] 实验7参考代码
- 思想实验(逻辑思维)解题
- 常用命令
- plsql 登录 01034 27101 , startup ORA-00119 ,ORA-00132
- GridControl获取同列多个汇总中的某一个汇总值
- Linux系统结构
- 生成格雷码(腾讯2016研发工程师编程题)
- 7.8.实验 解题参考
- HTML&CSS基础学习笔记1.9-添加图片
- POJ1321(DFS深搜)
- IO流
- hdu_5085_Counting problem(莫队分块思想)
- eclipse js 格式化的xml文件,直接导入到eclipse就可以用
- 自定义时间格式模板
- 李迅雷:大城市化和居民加杠杆能支撑房价多久
- LoRaWAN版本历史及协议格式说明