poj1015 正解--二维DP(完全背包)
题目链接:http://poj.org/problem?id=1015
错误解法:
网上很多解法是错误的,用dp[i][j]表示选择i个人差值为j的最优解,用path[i][j]存储路径,循环次序为“选的第几个人->选哪个人->差值之和”或者“选的第几个人->差值之和->选哪个人”,为了避免选择重复的人需要判断。错误的原因是存储路径的方式使得会覆盖一些情况,比如1 3 5和2 4 6均满足dp[3][k]最优时,若采用2 4 6作为dp[3][k]的最优解,而1 3 5 6是最终答案,那么此时6已经被dp[3][k]选择了,则得不到最终答案。
比如这组数据:
9 6
6 2
16 10
4 9
19 8
17 12
4 7
10 2
2 14
5 18
0 0
这组数据的正确答案是
Jury #1
Best jury has value 54 for prosecution and value 54 for defence:
1 2 3 4 6 9
但是错误程序的答案是
Jury #1
Best jury has value 52 for prosecution and value 52 for defence:
1 3 4 5 6 8
但由于poj这题的数据较弱,故这种解法也可以AC,uva323那道的数据较强,就会卡这种做法,错误解的代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std; int n,m,p,d,cas=,fix,S,A,D,P;
int dp[][],path[][],sub[],add[],res[]; bool is(int i,int j,int k){
while(i>){
if(path[i][j]==k)
return false;
j=j-sub[path[i][j]];i=i-;
}
return true;
} int main(){
while(scanf("%d%d",&n,&m)!=EOF&&n){
memset(dp,-,sizeof(dp));
memset(path,,sizeof(path));
fix=*m;
dp[][fix]=;
for(int i=;i<=n;i++){
scanf("%d%d",&p,&d);
sub[i]=p-d;
add[i]=p+d;
}
for(int i=;i<m;i++)
for(int j=;j<=*fix;j++)
if(dp[i][j]>=)
for(int k=;k<=n;k++)
if(is(i,j,k)&&dp[i][j]+add[k]>dp[i+][j+sub[k]]){
dp[i+][j+sub[k]]=dp[i][j]+add[k];
path[i+][j+sub[k]]=k;
}
int key;
for(key=;key<=fix;key++)
if(dp[m][fix+key]>=||dp[m][fix-key]>=)
break;
S=dp[m][fix+key]>dp[m][fix-key]?fix+key:fix-key;
A=dp[m][S];
for(int i=m,j=S;i>;){
res[i]=path[i][j];
j=j-sub[res[i]];
i--;
}
sort(res+,res+m+);
P=(A+(S-fix))/;D=(A-(S-fix))/;
printf("Jury #%d\n",cas++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",P,D);
for(int i=;i<=m;i++)
printf(" %d",res[i]);
printf("\n\n");
}
return ;
}
正解:
把循环次序改成“选哪个人->选的第几个人->差值之和”,并且使用vector<int> path[25][805]存储路径,从而可以存储所有情况,无法理解的话,就举个例子模拟模拟,而且是由于按照顺序遍历,最后的路径本身就是有序的。因为差值可能为负值,需要加一个修正值fix=m*20。循环部分就是完全背包模型,每个人的重量为1,背包重量为m,从1到n遍历每个人是否被选中,从m-1到0遍历背包的空间(因为每个人最多选一次,故倒序遍历)。详见代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std; int n,m,cas=,fix,p,d,S,A,P,D;
int dp[][],sub[],add[];
vector<int> path[][]; int main(){
while(~scanf("%d%d",&n,&m)&&n){
memset(dp,-,sizeof(dp));
for(int i=;i<=m;++i)
for(int j=;j<;++j)
path[i][j].clear();
fix=*m;
dp[][fix]=;
for(int i=;i<=n;++i){
scanf("%d%d",&p,&d);
sub[i]=p-d;
add[i]=p+d;
}
for(int i=;i<=n;++i)
for(int j=m-;j>=;--j)
for(int k=;k<=*fix;++k)
if(dp[j][k]>=)
if(dp[j][k]+add[i]>dp[j+][k+sub[i]]){
dp[j+][k+sub[i]]=dp[j][k]+add[i];
path[j+][k+sub[i]]=path[j][k];
path[j+][k+sub[i]].push_back(i);
}
int kk;
for(kk=;kk<=fix;++kk)
if(dp[m][fix+kk]>=||dp[m][fix-kk]>=)
break;
S=dp[m][fix+kk]>dp[m][fix-kk]?fix+kk:fix-kk;
A=dp[m][S];
P=(A+(S-fix))/,D=(A-(S-fix))/;
printf("Jury #%d\n",cas++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",P,D);
for(int i=;i<m;++i)
printf(" %d",path[m][S][i]);
printf("\n\n");
}
return ;
}
poj1015 正解--二维DP(完全背包)的更多相关文章
- (hdu)5234 Happy birthday 二维dp+01背包
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5234 Problem Description Today is Gorwin’s birt ...
- HDU - 2159 FATE(二维dp之01背包问题)
题目: 思路: 二维dp,完全背包,状态转移方程dp[i][z] = max(dp[i][z], dp[i-1][z-a[j]]+b[j]),dp[i][z]表示在杀i个怪,消耗z个容忍度的情况下 ...
- 2159 ACM 杭电 杀怪 二维费用的背包+完全背包问题
题意:已知经验值,保留的忍耐度,怪的种数和最多的杀怪数.求进入下一级的最优方案. 思路:用二维费用的背包+完全背包问题 (顺序循环)方法求解 什么是二维费用的背包问题? 问题: 二维费用的背包问题是指 ...
- 洛谷P1048 采药 二维dp化一维
题目描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个 ...
- 洛谷p1732 活蹦乱跳的香穗子 二维DP
今天不BB了,直接帖原题吧 地址>>https://www.luogu.org/problem/show?pid=1732<< 题目描述 香穗子在田野上调蘑菇!她跳啊跳,发现 ...
- 传纸条 NOIP2008 洛谷1006 二维dp
二维dp 扯淡 一道比较基本的入门难度的二维dp,类似于那道方格取数,不过走过一次的点下次不能再走(看提交记录里面好像走过一次的加一次a[i][j]的也AC了,,),我记得当年那道方格取数死活听不懂, ...
- 关于二维DP————站上巨人的肩膀
意匠惨淡经营中ing, 语不惊人死不休........ 前几天学了DP,做了个简单的整理,记录了关于DP的一些概念之类的,今天记录一下刚学的一个类型 ----关于二维DP 那建立二维数组主要是干嘛用的 ...
- BZOJ 2748: [HAOI2012]音量调节【二维dp,枚举】
2748: [HAOI2012]音量调节 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 2010 Solved: 1260[Submit][Statu ...
- To the Max 二维dp(一维的变形)
Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...
随机推荐
- Gitlab 项目上传
一,登陆gitab,新建reject Repository name: 仓库名称 Description(可选): 仓库描述介绍 Public, Private : 仓库权限(公开共享,私有或指定合作 ...
- 转载-JavaWeb学习总结
JavaWeb学习总结(五十三)——Web应用中使用JavaMail发送邮件 孤傲苍狼 2015-01-12 23:51 阅读:13407 评论:20 JavaWeb学习总结(五十二)——使用 ...
- 用HTML5播放IPCamera视频
HTML5增加了vedio标签,能直接播放视频,但是播放的格式是有限的. 这里将IPCamera的视频转换OGG格式,再通过HTML5网页播放,播放还是很清晰的.IPCamera要支持RTSP等视频流 ...
- Spring bean注解配置(1)
Spring自带的@Component注解及扩展@Repository.@Service.@Controller,如图 在使用注解方式配置bean时,需要引进一个包: 使用方法: 1.为需要使用注解方 ...
- 10-19 dp专练
dp专练,终于克服了一次自己对dp的恐惧,磕出来一道题. 得分情况: T1:0 T2:0 T3:0 emmmm,磕出来的题是T2,但是因为初始化和int long long的原因爆零了 T1:n只狼排 ...
- 腾讯优图&港科大提出一种基于深度学习的非光流 HDR 成像方法
目前最好的高动态范围(HDR)成像方法通常是先利用光流将输入图像对齐,随后再合成 HDR 图像.然而由于输入图像存在遮挡和较大运动,这种方法生成的图像仍然有很多缺陷.最近,腾讯优图和香港科技大学的研究 ...
- 显式锁(四)Lock的等待通知机制Condition
任意一个Java对象,都拥有一组监视器方法(定义在根类Object上),主要包括:wait( ).wait(long timeout).notify().notifyAll()方法:这些方法与关 ...
- python对象转字典
1.基础实现 class TestDict: name = "wyb" age = " def __init__(self): self.gender = 'male' ...
- 框架之Tornado(简单介绍)
引言 回想Django的部署方式 以Django为代表的python web应用部署时采用wsgi协议与服务器对接(被服务器托管),而这类服务器通常都是基于多线程的,也就是说每一个网络请求服务器都会有 ...
- OpenCL 双调排序 CPU 版
▶ 学习了双调排序,参考(https://blog.csdn.net/xbinworld/article/details/76408595) ● 使用 CPU 排序的代码 #include <s ...