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 ...
随机推荐
- LNMP中常见的502错误及处理方法
LNMP配置完成以后,经常遇到502 Bad Gateway的错误提示,究其原因多为2种.下面对这两方面的问题进行分析: 1. 配置方面的错误 配置错误中,或者因为php-fpm找不到路径,或者是权限 ...
- BOM及改变this指向
bom ( borwser object model 浏览器对象模型) 定义js操作浏览器的属性和方法 window.open(url way()) 中有两个参数 url代表打开的网页地址 wa ...
- Work01
7101:我是最酷的张绥:我的爱是弹吉他,唱歌,游泳,打篮球...: 我的博客是:https://www.cnblogs.com/Mrzs/ 我的码云个人主页是:https://gitee.com/s ...
- phpstorm使用教程
phpstorm包含了webstorm的全部功能,更能够支持php代码.PhpStorm是一个轻量级且便捷的PHP IDE,其旨在提供用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时 ...
- 修改 Docker-MySQL 容器的 默认用户加密规则
背景介绍 今天开始做集成测试,需要把程序和环境重新部署在新的服务器上.项目的环境都是基于Docker来的,所以数据库也是选择从Docker官网上面拉官方的MySQL镜像.(Tag = 8.0.12) ...
- MySQL 创建数据库的两种方法
使用 mysqladmin 创建数据库 使用普通用户,你可能需要特定的权限来创建或者删除 MySQL 数据库. 所以我们这边使用root用户登录,root用户拥有最高权限,可以使用 mysql mys ...
- Javascript获取数组中的最大值和最小值的方法汇总
比较数组中数值的大小是比较常见的操作,下面同本文给大家分享四种放哪广发获取数组中最大值和最小值,对此感兴趣的朋友一起学习吧 比较数组中数值的大小是比较常见的操作,比较大小的方法有多种,比如可以使用 ...
- FlexPaper及二次开发
Flexpaper二次开发入门教程 http://ajava.org/course/web/?page=2
- IP 别名和辅助 IP 地址
https://blog.csdn.net/xiewen99/article/details/54729112?utm_source=itdadao
- Eclipse “cannot be resolved to a type”
遇到这坑爹的问题,网上各种答案. 只有这个能解决我的问题,eclipse机制问题: Eclipse “cannot be resolved to a type”