博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ZOJ-3524 拓扑排序+完全背包(好题)
阅读量:5079 次
发布时间:2019-06-12

本文共 2298 字,大约阅读时间需要 7 分钟。

题意:在一个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
using namespace std;const int N=600+10;const int M=6e4+10;int n,m,W,s,Maxv,Mint,deg[N],w[N],v[N];vector
V;int cnt=0,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
q;void toposort() { for (int i=1;i<=n;i++) if (deg[i]==0) 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]==0) q.push(y); } }}bool vis[N];int dp[N][2010],tp[N][2010];void solve() { memset(dp,0,sizeof(dp)); memset(tp,0x3f,sizeof(tp)); memset(vis,0,sizeof(vis)); vis[s]=1; dp[s][0]=0; tp[s][0]=0; for (int i=0;i
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]=1; for (int k=0;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=0;j<=W;j++) if (dp[x][j]>Maxv || dp[x][j]==Maxv && tp[x][j]

 

转载于:https://www.cnblogs.com/clno1/p/10940191.html

你可能感兴趣的文章
轻松学MVC4.0–6 MVC的执行流程
查看>>
redis集群如何清理前缀相同的key
查看>>
Python 集合(Set)、字典(Dictionary)
查看>>
获取元素
查看>>
proxy写监听方法,实现响应式
查看>>
第一阶段冲刺06
查看>>
十个免费的 Web 压力测试工具
查看>>
EOS生产区块:解析插件producer_plugin
查看>>
mysql重置密码
查看>>
jQuery轮 播的封装
查看>>
一天一道算法题--5.30---递归
查看>>
JS取得绝对路径
查看>>
排球积分程序(三)——模型类的设计
查看>>
python numpy sum函数用法
查看>>
php变量什么情况下加大括号{}
查看>>
linux程序设计---序
查看>>
【字符串入门专题1】hdu3613 【一个悲伤的exkmp】
查看>>
C# Linq获取两个List或数组的差集交集
查看>>
HDU 4635 Strongly connected
查看>>
ASP.NET/C#获取文章中图片的地址
查看>>