题目链接: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(完全背包)的更多相关文章

  1. (hdu)5234 Happy birthday 二维dp+01背包

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5234 Problem Description Today is Gorwin’s birt ...

  2. 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个容忍度的情况下 ...

  3. 2159 ACM 杭电 杀怪 二维费用的背包+完全背包问题

    题意:已知经验值,保留的忍耐度,怪的种数和最多的杀怪数.求进入下一级的最优方案. 思路:用二维费用的背包+完全背包问题 (顺序循环)方法求解 什么是二维费用的背包问题? 问题: 二维费用的背包问题是指 ...

  4. 洛谷P1048 采药 二维dp化一维

    题目描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个 ...

  5. 洛谷p1732 活蹦乱跳的香穗子 二维DP

    今天不BB了,直接帖原题吧  地址>>https://www.luogu.org/problem/show?pid=1732<< 题目描述 香穗子在田野上调蘑菇!她跳啊跳,发现 ...

  6. 传纸条 NOIP2008 洛谷1006 二维dp

    二维dp 扯淡 一道比较基本的入门难度的二维dp,类似于那道方格取数,不过走过一次的点下次不能再走(看提交记录里面好像走过一次的加一次a[i][j]的也AC了,,),我记得当年那道方格取数死活听不懂, ...

  7. 关于二维DP————站上巨人的肩膀

    意匠惨淡经营中ing, 语不惊人死不休........ 前几天学了DP,做了个简单的整理,记录了关于DP的一些概念之类的,今天记录一下刚学的一个类型 ----关于二维DP 那建立二维数组主要是干嘛用的 ...

  8. BZOJ 2748: [HAOI2012]音量调节【二维dp,枚举】

    2748: [HAOI2012]音量调节 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 2010  Solved: 1260[Submit][Statu ...

  9. To the Max 二维dp(一维的变形)

    Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...

随机推荐

  1. 通过shell进行数学计算

    对于基本运算,可以使用let, $(())和$[] 对于高级运算,使用expr和bc这两个工具 [hupeng@hupeng-vm shell]$n1= [hupeng@hupeng-vm shell ...

  2. orace学习操作(2)

    一.Oracle视图 视图是虚表,没有具体物理数据,是通过实体表的一种计算映射逻辑.主要就是为了方便和数据安全: 实际当中的数据依然存在我们的实际表里面,只不过取数据的时候根据这个视图(子查询)从实际 ...

  3. 1114 Family Property (25 分)

    1114 Family Property (25 分) This time, you are supposed to help us collect the data for family-owned ...

  4. RAID磁盘阵列的原理与搭建

    学习导图 RAID-0结构关系图 RAID-1结构关系图 RAID-5:条带+分布校验(三块磁盘以上) RAID-10:镜像+条带(四块磁盘以上) RAID-0 添加两块硬盘,分别为磁盘1.磁盘2.最 ...

  5. JQUERY dialog的用法详细解析

    本篇文章主要是对JQUERY中dialog的用法进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助 今天用到了客户端的对话框,把 jQuery UI 中的对话框学习了一下. 准备 jQ ...

  6. 使用Golang进行性能分析(Profiling)

    转自:http://www.cppblog.com/sunicdavy/archive/2015/04/11/210308.html 本文介绍游戏服务器的性能分析, web服务器性能分析不在本文分析范 ...

  7. 对话框(VC_Win32)

    资源描述表中对话框定义 格式: 对话框名 DIALOG[载入特性] X,Y,Width,Height[设置选项] { 对话框控件定义; } 说明: 对话框名称: 标识对话框资源,可为一个字符串也可以为 ...

  8. php while循环控制实例讲解

    while循环是PHP中最简单的循环,其基本格式为: while (expr){ statement } 或者 while (expr): statement endwhile; 该语法表示,只要ex ...

  9. 图文并茂 RAID 技术全解 – RAID0、RAID1、RAID5、RAID100

    RAID 技术相信大家都有接触过,尤其是服务器运维人员,RAID 概念很多,有时候会概念混淆.这篇文章为网络转载,写得相当不错,它对 RAID 技术的概念特征.基本原理.关键技术.各种等级和发展现状进 ...

  10. blktrace未公开选项网络保存截取数据

    本文链接地址: blktrace未公开选项网络保存截取数据 我们透过blktrace来观察io行为的时候,第一件事情需要选择目标设备,以便分析该设备的io行为.具体使用可以参考我之前写的几篇:这里 这 ...