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 ...
随机推荐
- Jsoncpp 使用方法大全
Json(JavaScript Object Notation )是一种轻量级的数据交换格式.简而言之,Json组织形式就和python中的字典, C/C++中的map一样,是通过key-value对 ...
- 学习笔记之Redis
Redis https://redis.io/ redis.cn http://www.redis.cn/ Azure Redis Cache Documentation - Tutorials, A ...
- C++ 无锁队列实现
上源码 #ifndef __GLOBAL_LOCK_FREE_QUEUE_H__ #define __GLOBAL_LOCK_FREE_QUEUE_H__ #include <atomic> ...
- 基本数据结构:链表(list)
copy from:http://www.cppblog.com/cxiaojia/archive/2012/07/31/185760.html 基本数据结构:链表(list) 谈到链表之前,先说一下 ...
- guess_age
age_shanshan = 18count = 3num = 0while num < count: age = int(input("age:")) if age == ...
- python3 string
字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello World!' var2 ...
- django (文件操作)
文件传输html中 form表单必须写 文件的一个属性 enctype="multipart/form-data" file_obj = request.FILES.get('fi ...
- 经典算法 KMP算法详解
内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...
- 开源推荐系统Librec中recommender模块算法了解——cf模块
1. k近邻(k-NearestNeighbor)算法介绍及在推荐系统中的应用 https://zhuanlan.zhihu.com/p/25994179 k近邻(k-NearestNeig ...
- 阻止form提交数据,通过ajax等上传数据
btn.click(function (event) { event.preventDefault(); // 组织发送 $.ajax({ ...}) })