ZOJ-3524 拓扑排序+完全背包(好题)
题意:在一个DAG上,主角初始有W钱起点在s点,每个点有一个代价wi和价值vi,主角从起点走到某一点不能回头走,一路上可以买东西(一个点的东西可以买无限次),且体力消耗为身上负重*路径长度。主角可以在任意一点停止旅程,问在获得最大价值情况下体力消耗最小。
解法:第一次遇到这类型的题,看大佬题解,这里说下自己的理解。首先主角在DAG上走且不能回头,那么比较明显让我们想到按拓扑排序顺序进行dp,这是正确的但是代码实现可能不那么容易想:我们首先对DAG进行拓扑排序求出它的拓扑序V,按照拓扑序进行完全背包的DP,这里要注意一点就是因为主角是有起点的,所以有的地方是根本到达不到的,我们可以用个vis数组来代表主角能到达的点,能动到达的点才能DP。DP思路是:设计状态dp[x][j]为走到x点,容量为j的最大价值,同时tp[x][j]为最大价值为dp[x][j]时候的最小体力消耗,那么我们到一个新点,我们先对这个的的物品做完全背包,然后用这个点x去更新x的下一步y的状态(这也是拓扑序DP的核心)。DP的同时更新答案即可。
这里提出一个问题就是为什么在两个限制下要求的答案dp状态不用设计成三维的呢?设计成两位状态能保证是在容量限制下最大价值且在最大价值下的最小消耗吗?这个问题蒟蒻一开始想不通,这是因为答案只要最好的。当然也可以把状态设计成例如dp[x][j][k]代表到x点容量为j价值为k的最小体力消耗,但是注意到因为题目要求的是最大价值下的最小消耗,所以这个状态的除了dp[x][j][Maxv](Maxv是x点容量j的最大价值)是有用的,其他的都是没用的dp[x][j][val] (val<Maxv)。因为此时容量已经确定,那么以后的状态在这些状态中容量相等的肯定选价值最大的,其他价值小的不会对后面结果造成任何影响。
除此以为这道题还有一些细节,不懂的建议看代码理解:
#include<bits/stdc++.h>
using namespace std;
const int N=+;
const int M=6e4+;
int n,m,W,s,Maxv,Mint,deg[N],w[N],v[N];
vector<int> V; int cnt=,head[N],nxt[M],to[M],len[M];
void add_edge(int x,int y,int z) {
nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
} queue<int> q;
void toposort() {
for (int i=;i<=n;i++) if (deg[i]==) q.push(i);
while (!q.empty()) {
int x=q.front(); q.pop();
V.push_back(x);
for (int i=head[x];i;i=nxt[i]) {
int y=to[i];
if (--deg[y]==) q.push(y);
}
}
} bool vis[N];
int dp[N][],tp[N][];
void solve() {
memset(dp,,sizeof(dp));
memset(tp,0x3f,sizeof(tp));
memset(vis,,sizeof(vis)); vis[s]=;
dp[s][]=; tp[s][]=;
for (int i=;i<V.size();i++) {
if (!vis[V[i]]) continue;
int x=V[i];
for (int j=w[x];j<=W;j++)
if (dp[x][j-w[x]]+v[x]>dp[x][j]) dp[x][j]=dp[x][j-w[x]]+v[x],tp[x][j]=tp[x][j-w[x]];
else if (dp[x][j-w[x]]+v[x]==dp[x][j]) tp[x][j]=min(tp[x][j],tp[x][j-w[x]]);
for (int j=head[x];j;j=nxt[j]) {
int y=to[j];
vis[y]=;
for (int k=;k<=W;k++)
if (dp[x][k]>dp[y][k]) {
dp[y][k]=dp[x][k];
tp[y][k]=tp[x][k]+len[j]*k;
} else if (dp[y][k]==dp[x][k]) {
int tmp=tp[x][k]+len[j]*k;
tp[y][k]=min(tp[y][k],tmp);
}
}
for (int j=;j<=W;j++)
if (dp[x][j]>Maxv || dp[x][j]==Maxv && tp[x][j]<Mint) {
Maxv=dp[x][j]; Mint=tp[x][j];
}
}
} int main()
{
while (scanf("%d%d%d%d",&n,&m,&W,&s)==) {
for (int i=;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
memset(deg,,sizeof(deg));
cnt=; memset(head,,sizeof(head));
for (int i=;i<=m;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z); deg[y]++;
}
V.clear(); toposort();
Maxv=; Mint=0x3f3f3f3f;
solve();
printf("%d\n",Mint);
}
return ;
}
ZOJ-3524 拓扑排序+完全背包(好题)的更多相关文章
- zoj 3524(拓扑排序+多重背包)(好题)
http://blog.csdn.net/woshi250hua/article/details/7824773 题目大意:从前有n座山,山里都有一座庙,庙里都有一个老和尚,老和尚专送纪念品,每个纪念 ...
- Crazy Shopping(拓扑排序+完全背包)
Crazy Shopping(拓扑排序+完全背包) Because of the 90th anniversary of the Coherent & Cute Patchouli (C.C. ...
- ZOJ 4124 拓扑排序+思维dfs
ZOJ - 4124Median 题目大意:有n个元素,给出m对a>b的关系,问哪个元素可能是第(n+1)/2个元素,可能的元素位置相应输出1,反之输出0 省赛都过去两周了,现在才补这题,这题感 ...
- E - Ingredients 拓扑排序+01背包
题源:https://codeforces.com/gym/101635/attachments 题意: n行,每行给定字符串s1,s2,s3代表一些菜谱名.s2和s3是煮成是的必要条件,然后给出c和 ...
- HDU 3342 -- Legal or Not【裸拓扑排序 &&水题 && 邻接表实现】
Legal or Not Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...
- 第十二届湖南省赛 (B - 有向无环图 )(拓扑排序+思维)好题
Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始.点 v 结束的路径). 为了方便,点用 1,2,…,n 编号. 设 count(x,y) 表示点 x 到点 y ...
- C#LeetCode刷题-拓扑排序
拓扑排序篇 # 题名 刷题 通过率 难度 207 课程表 40.0% 中等 210 课程表 II 39.8% 中等 329 矩阵中的最长递增路径 31.0% 困难
- poj 3687 Labeling Balls(拓扑排序)
题目:http://poj.org/problem?id=3687题意:n个重量为1~n的球,给定一些编号间的重量比较关系,现在给每个球编号,在符合条件的前提下使得编号小的球重量小.(先保证1号球最轻 ...
- [ACM] POJ 3687 Labeling Balls (拓扑排序,反向生成端)
Labeling Balls Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10161 Accepted: 2810 D ...
随机推荐
- 【知识强化】第六章 查找 6.3 B树和B+树
本节课我们来学习本章的第一个难点,就是B树.那么B树它其实是一种数据结构,我们设计出这种数据结构就是为了提高我们的查找效率的,提高我们在磁盘上的查找效率.那么什么是B树呢?了解B树之前,我们先来回忆一 ...
- 2018-2-22-在-windows-安装-Jekyll
title author date CreateTime categories 在 windows 安装 Jekyll lindexi 2018-02-22 17:47:39 +0800 2018-2 ...
- 【串线篇】SpringMvc源码分析
一.DispathcherServlet结构分析 1).所有请求过来DispatcherServlet收到请求, 2).调用doDispatch()方法进行处理 1).getHandler():根据当 ...
- JavaSE---多线程---Callable、Future
1.概述 1.1 JDK1.5后,Java提供了Callable接口,该接口提供一个call方法作为线程执行体,该call方法可以 有返回值.声明抛出异常: 因此,我们可以直接将Callable接口 ...
- 【纪中集训】2019.08.10【NOIP提高组】模拟 A 组TJ
T1 Description Solution 有待填坑-- T2 Description 给定一个\(h(≤10)\)层.\(n(≤10)\)行.\(m(≤10)\)列的由泥土组成的立方体,挖开\( ...
- 洛谷P2786 英语1(eng1)- 英语作文
题目背景 蒟蒻HansBug在英语考场上,挠了无数次的头,可脑子里还是一片空白. 题目描述 眼下出现在HansBug蒟蒻面前的是一篇英语作文,然而智商捉急的HansBug已经草草写完了,此时 他发现离 ...
- layui导出表格全部数据
layui自带的导出表格,只能导出当前页面,如果当前页包含全部数据,那不就是导出全部数据了吗,所以我给导出事件单独定义了一个请求,当触发这个请求时,在后台查询数据时不要按接收的page 和 limit ...
- Android学习--写一个发送短信的apk,注意布局文件的处理过程!!!
刚开始写Android程序如图发现使用了findViewById方法之后输出的话居然是null(空指针错误),也就是说这个方法没有成功.网上说这样写是在activity_main .xml去找这个ID ...
- Python之-在字典、列表、集合中刷选数据
一.元组.字典.列表的遍历 1.元组遍历 元组的遍历借助 range() 函数,基本思想是通过元组的长度使用for循环进行遍历 #troup s = ["aaa","bb ...
- (转)使用OpenGL显示图像(四)运用投影与相机视角
运用投影与相机视角 编写:jdneo - 原文:http://developer.android.com/training/graphics/opengl/projection.html 在OpenG ...