### 洛谷 P2656 题目链接 ###

题目大意:

小胖和ZYR要去ESQMS森林采蘑菇。

ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。

比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.

现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。

分析:

1、题目没有限定路走的次数,显然如果图中有强连通分量(即有向环),那么这个环中的所有边都可以无数次访问,直到所有边能采到的蘑菇数量为 0 ,即为该连通分量的最大价值,故先进行缩点。

2、缩点之后,全图变为DAG图,然后每个点有价值,其次每条边有价值(且这个价值不会再乘以 恢复系数 ,因为缩点后不可能再走第二次)。那么求一些缩点与边权的最大价值,故用 DP 解答。

3、本题还要注意的是,它会给你一个起点,所以在拓扑排序中,在这个起点上面的点可以直接忽略,当然我们也可以全部初始化为负无穷,然后设起点 DP 值为该点的价值(如果这个起点是缩点的话,否则价值是 0 的),这样求最大值的时候,所有状态只会从起点转移,就不用将起点上面的点排除了,更方便。

代码如下:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#define maxn 80008
using namespace std;
int n,m,cnt,tot,Index,sum,st;
int low[maxn],dfn[maxn],flag[maxn],head[maxn],q[maxn];
int pre[maxn],s[maxn],in[maxn],qhead[maxn];
int b[maxn],dp[maxn];
bool vis[maxn];
struct Edge
{
int to;
int val;
double t;
int next;
}edge[];
struct EDGE
{
int to;
int val;
int next;
}E[];
inline void add(int u,int v,int w,double t)
{
edge[++cnt].to=v;
edge[cnt].val=w;
edge[cnt].t=t;
edge[cnt].next=head[u];
head[u]=cnt;
return;
}
inline void qadd(int u,int v,int w)
{
E[++cnt].to=v;
E[cnt].val=w;
E[cnt].next=qhead[u];
qhead[u]=cnt;
return;
}
void tarjan(int u)
{
low[u]=dfn[u]=++Index;
q[++tot]=u;
vis[u]=true;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
++sum;//缩点的序号
do{
pre[q[tot]]=sum;
vis[q[tot--]]=false;
}while(q[tot+]!=u);
}
return;
}
void topo()
{
queue<int> Q;
while(!Q.empty()) Q.pop();
for(int i=;i<=sum;i++){
if(!in[i]) Q.push(i);
}
while(!Q.empty())
{
int x=Q.front();
Q.pop();
b[++cnt]=x,dp[x]=-0x3f3f3f3f;//记住要初始化为负无穷,不然会 WA 一个点
for(int i=qhead[x];i;i=E[i].next){
int v=E[i].to;
in[v]--;
if(!in[v]) Q.push(v);
}
}
return;
}
int main()
{
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
scanf("%d%d",&n,&m);
int A,B,C;
double D;
for(int i=;i<=m;i++){
scanf("%d%d%d%lf",&A,&B,&C,&D);
add(A,B,C,D);
}
scanf("%d",&st);
for(int i=;i<=n;i++){if(!dfn[i]) tarjan(i);}
cnt=;
for(int i=;i<=n;i++){
for(int j=head[i];j;j=edge[j].next){
int v=edge[j].to;
if(pre[i]!=pre[v]){qadd(pre[i],pre[v],edge[j].val);in[pre[v]]++;}
else{
int ans=edge[j].val;
int res=edge[j].val*edge[j].t;
while(res){ //算这个缩点的总价值,即按题意把所有边乘到为 0
ans+=res;
res=res*edge[j].t;
}
s[pre[i]]+=ans;
}
}
}
cnt=;
topo();//保证有向图 DP 顺序
dp[pre[st]]=s[pre[st]];//标记从起点所代表的缩点上为初始态转移
for(int i=;i<=cnt;i++){
int u=b[i];
for(int j=qhead[u];j;j=E[j].next){
int v=E[j].to;
dp[v]=max(dp[v],dp[u]+E[j].val+s[v]);
}
}
int ans=-0x3f3f3f3f;
for(int i=;i<=cnt;i++) ans=max(ans,dp[i]);
printf("%d\n",ans );
}

洛谷 P2656 (缩点 + DAG图上DP)的更多相关文章

  1. 动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序

    洛谷P4017 最大食物链计数 这是洛谷一题普及/提高-的题目,也是我第一次做的一题 图上动态规划/拓扑排序 ,我认为这题是很好的学习拓扑排序的题目. 在这题中,我学到了几个名词,入度,出度,及没有环 ...

  2. zoj1232Adventure of Super Mario(图上dp)

    题目连接: 啊哈哈.点我点我 思路: 这个题目是一个图上dp问题.先floyd预处理出图上全部点的最短路,可是在floyd的时候,把可以用神器的地方预处理出来,也就是转折点地方不能为城堡..预处理完成 ...

  3. 洛谷 P6295 - 有标号 DAG 计数(生成函数+容斥+NTT)

    洛谷题面传送门 看到图计数的题就条件反射地认为是不可做题并点开了题解--实际上这题以我现在的水平还是有可能能独立解决的( 首先连通这个条件有点棘手,我们尝试把它去掉.考虑这题的套路,我们设 \(f_n ...

  4. BZOJ5291/洛谷P4458/LOJ#2512 [Bjoi2018]链上二次求和 线段树

    原文链接http://www.cnblogs.com/zhouzhendong/p/9031130.html 题目传送门 - LOJ#2512 题目传送门 - 洛谷P4458 题目传送门 - BZOJ ...

  5. 【BZOJ2763/洛谷p4563】【分层图最短路】飞行路线

    2763: [JLOI2011]飞行路线 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4630  Solved: 1797[Submit][Stat ...

  6. Tarjan缩点+DAG图dp

    题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...

  7. 洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)

    题面 传送门(loj) 传送门(洛谷) 题解 我果然是人傻常数大的典型啊-- 题解在这儿 //minamoto #include<bits/stdc++.h> #define R regi ...

  8. 【洛谷 P4934】 礼物 (位运算+DP)

    题目链接 位运算+\(DP\)=状压\(DP\)?(雾 \(a\&b>=min(a,b)\)在集合的意义上就是\(a\subseteq b\) 所以对每个数的子集向子集连一条边,然后答案 ...

  9. 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门

    dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...

随机推荐

  1. webUploader的使用

    webUploader的使用记录 WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML ...

  2. Oracle基础教程(一)

    本文链接:https://blog.csdn.net/GoldenKitten/article/details/84947386 以下内容为转载以上博客,自己做了略微的补充,如需查看原文,请点击上面的 ...

  3. MySQL 中的外键

    表和表之间可存在引用关系,这在抽象数据到表时,是很常见的.这种联系是通过在表中创建外键(foreign key)来实现的. 比如一个订单,可能关联用户表和产品表,以此来记录谁买了什么产品. 约定两个概 ...

  4. Python爬虫反反爬:CSS反爬加密彻底破解!

    刚开始搞爬虫的时候听到有人说爬虫是一场攻坚战,听的时候也没感觉到特别,但是经过了一段时间的练习之后,深以为然,每个网站不一样,每次爬取都是重新开始,所以,爬之前谁都不敢说会有什么结果. 前两天,应几个 ...

  5. Java的23种设计模式,详细讲解(三)

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  6. Python笔记:设计模式之工厂模式

    工厂模式:“工厂”即表示一个负责创建其他类型的对象的类,通常情况下,一个工厂的对象会有一个或多个方法与之关联,这些方法用于创建不同类型的对象,工厂对象会根据客户端给方法传递的不同的参数或者客户端调用不 ...

  7. 接口测试基础--Fiddler、Postman、Python实现对接口的测试

    写在前面:本文主要的章节规划: 1.什么是接口测试    另外,有的时候会直接调用别的公司的接口,比如银行的.淘宝的.支付宝的,此时也需要做接口测试以及验证数据: 做接口测试的好处:      其中, ...

  8. python基础—条件语句

    一.Python基础 1.第一句python print('hello,world') Q: 后缀名可以任意? A:  导入模块时,如果不是.py后缀,会出错. 2.两种执行的方式: -python解 ...

  9. WebService 接收JSON字符串

    晚上学习时公司的同事,暂且叫A吧,A:“我们公司XXX纺织的AM接口不通,让我看下”,我:“接口写的不是有AJAX异步请求的示例嘛,参考下,我都测试过接口,都是通的.”,A:“我走的不是AJAX,走的 ...

  10. RPM包安装——手动安装

    RPM包安装 手动安装 挂载光盘 首先查看光盘是否挂载(使用mount命令) RPM包存放位置 在你光盘挂载点的Packages目录下 使用 ll | grep 关键字 可以快速找到你想要的RPM包 ...