题目链接: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. 小峰mybatis(1) 处理clob,blob等。。

    一.mybatis处理CLOB.BLOB类型数据 CLOB:大文本类型:小说啊等大文本的:对应数据库类型不一致,有long等: BLOB:二进制的,图片:电影.音乐等二进制的: 在mysql中: bl ...

  2. 杂项:Mantis

    ylbtech-杂项:Mantis 缺陷管理平台Mantis,也做MantisBT,全称Mantis Bug Tracker.Mantis是一个基于PHP技术的轻量级的开源缺陷跟踪系统,以Web操作的 ...

  3. git clone的时候filename too long解决办法

    在git bash中,运行下列命令: git config --global core.longpaths true

  4. oracle 用函数返回对象集合

    1.先要声明全局type:并且,字段变量类型要为object,不能为record: (1)CREATE OR REPLACE TYPE "DDD_BY_DEPT_STATISTISC&quo ...

  5. Hibernate inverse反转

    inverse: inverse: 指定由哪一方来维护之间的关联关系 false默认,表示不放弃,是主动放 true:表示把关联关系的维护反转(放弃),对集合对象的修改不会被反映到数据库中 容易出现的 ...

  6. final修饰的类有什么特点

    变量定义为final,一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变. 方法定义为final,是为了防止任何继承类改变它. 类定义为final, ...

  7. JavaScript的灵活应用

    1.查找数组的最大值和最小值 (1) Math.max.qpply(null,array); Math.min.qpply(null,array); (2) eval("Math.max(& ...

  8. PL/SQL 的一些用法

    变量的声明,赋值,打印(declare是pl/sql里面的用法 variable是sql*plus里面的用法,variable相当于一个sql*plus环境的全局变量,declare里定义的是pl/s ...

  9. Bogart SysPwd.vb

    Module syspwd Public Const STR_MASK = "MyFunction" '加密用字串 '預定義密碼長度 Public GintCheckPwd As ...

  10. YUM软件包额外扩展了解项

    5.YUM配置文件 yum的配置一般有两种方式: 一种是直接配置/etc目录下的yum.conf文件, 另外一种是在/etc/yum.repos.d目录下增加.repo文件 [root@xuliang ...