题解【luogu1073 最优贸易】
Solution
考虑原图是 DAG 时怎么做。
拓扑排序 + dp ,令 dp[i] 表示 \(1\) 到 \(i\) 的路径上最小的卖出价格。转移方程就是对每一个可以到达这个点的 dp 取个 min ,计算答案便是 \(\max \limits _{i} \{val_i - dp_i \}\) ,其中 val 是商品价格。dp 在拓扑序上随便转移一下就好
考虑题目怎么做便十分显然,直接缩点得到一张 DAG ,贪心的让缩完的点的卖出价格是该点中价值最大的,卖入的是该点中价值最小的。然后就可以用在 DAG 上转移的方法来做就可以了
A Very Important thing
:
在更新答案的时候,需要判断这个点是否能到达 n 点所在的强连通分量里。实现方法是在 反图上 dfs 一遍就可以判断出那些点能够到达终点。
Code
#include <bits/stdc++.h>
#define INF 1000000000
using namespace std;
const int N = 100100;
const int M = 500500;
int n, m, val[N], cnt, dfn[N], low[N], tot, U[N], V[N], ind[N], ins[N], vis[N];
int scc, bel[N], Max[N], Min[N], List[N], ans, dp[N], sta[N], top, z[N];
struct edge {
int v; edge *next;
}pool[M * 6], *head[N], *h[N], *hh[N];
inline void addd(int u, int v) {
edge *p = &pool[++cnt];
p->v = v, p->next = hh[u], hh[u] = p;
}
inline void add(int u, int v) {
edge *p = &pool[++cnt];
p->v = v, p->next = h[u], h[u] = p;
}
inline void addedge(int u, int v) {
edge *p = &pool[++cnt];
p->v = v, p->next = head[u], head[u] = p;
}
inline void tarjan(int u) {
dfn[u] = low[u] = ++tot; ins[u] = 1, sta[++top] = u;
for(edge *p = head[u]; p; p = p->next) {
int v = p->v;
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v]) low[u] = min(low[u], dfn[v]);
} if(low[u] == dfn[u]) {
++scc;
while(sta[top + 1] != u) {
Max[scc] = max(Max[scc], val[sta[top]]);
Min[scc] = min(Min[scc], val[sta[top]]);
bel[sta[top]] = scc; ins[sta[top--]] = 0;
}
}
}
inline void toposort() {
tot = 0; queue <int> Q;
while(!Q.empty()) Q.pop();
for(int i = 1; i <= scc; i++)
if(!ind[i]) Q.push(i);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
List[++tot] = u;
for(edge *p = h[u]; p; p = p->next) {
int v = p->v; ind[v]--;
if(ind[v] == 0) Q.push(v);
}
}
}
inline void dfs(int u) {
if(vis[u]) return ; vis[u] = 1;
for(edge *p = hh[u]; p; p = p->next) dfs(p->v);
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
for(int i = 1; i <= n; i++) Min[i] = INF, Max[i] = -INF;
for(int i = 1; i <= m; i++) {
scanf("%d %d %d", &U[i], &V[i], &z[i]);
addedge(U[i], V[i]);
if(z[i] == 2) addedge(V[i], U[i]);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= m; i++) {
int x = bel[U[i]], y = bel[V[i]];
if(x != y) { add(x, y), ind[y]++, addd(y, x);
if(z[i] == 2) add(y, x), ind[x]++, addd(x, y);
}
} toposort(); dfs(bel[n]);
for(int i = 1; i <= scc; i++) dp[i] = Min[i];
for(int i = 1; i <= scc; i++) {
int u = List[i];
if(vis[u]) ans = max(ans, Max[u] - dp[u]);
for(edge *p = h[u]; p; p = p->next) {
int v = p->v; dp[v] = min(dp[v], dp[u]);
}
}
printf("%d\n", ans);
return 0;
}
题解【luogu1073 最优贸易】的更多相关文章
- luogu1073 最优贸易 (tarjan+dp)
tarjan缩点,然后按照拓扑序,做1号点能到达的点的答案具体做法是对每个点记一个min[i],max[i],vis[i]和ans[i]做拓扑序的时候,假设在从u点开始做,有边u到v,如果vis[u] ...
- 「NOIP2009」最优贸易 题解
「NOIP2009」最优贸易 题解 题目TP门 题目描述 \(C\)国有\(n\)个大城市和\(m\)条道路,每条道路连接这\(n\)个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 ...
- 【洛谷P1073】[NOIP2009]最优贸易
最优贸易 题目链接 看题解后感觉分层图好像非常NB巧妙 建三层n个点的图,每层图对应的边相连,权值为0 即从一个城市到另一个城市,不进行交易的收益为0 第一层的点连向第二层对应的点的边权为-w[i], ...
- [NOIP2009]最优贸易(图论)
[NOIP2009]最优贸易 题目描述 CC 国有 \(n\) 个大城市和 \(m\) 条道路,每条道路连接这 \(n\) 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 \(m\ ...
- NOIP2009 最优贸易
3. 最优贸易 (trade.pas/c/cpp) [问题描述] C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个城市之间 多只有一条道路直接相连.这 m 条道 ...
- Codevs 1173 最优贸易 2009年NOIP全国联赛提高组
1173 最优贸易 2009年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description [问题描述] C 国有n ...
- Luogu P1073 最优贸易
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双 ...
- 洛谷 P1073 最优贸易 解题报告
P1073 最优贸易 题目描述 \(C\)国有\(n\)个大城市和\(m\)条道路,每条道路连接这\(n\)个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这\(m\)条道路中有一部分 ...
- CH6101 最优贸易【最短路】
6101 最优贸易 0x60「图论」例题 描述 C国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通 ...
随机推荐
- 【转】从零开始学习Skynet_examples研究
转自 http://blog.csdn.net/mr_virus/article/details/52330193 一.编译Skynet: 1.用ubuntu15.10直接 make linux 编译 ...
- Android开发-API指南-<uses-permission>
<uses-permission> 英文原文:http://developer.android.com/guide/topics/manifest/uses-permission-elem ...
- Skype for Business Server 方案
方案说明: 高可用性的配置屏蔽了单点故障,使得当一个服务器节点失效时,另外的可用的节点能够进行服务的接管.可伸缩性的配置可以保证当即时沟通平台的使用用户增加时,该平台应该具有良好的可伸缩性,能非常方便 ...
- 棋盘问题:dfs
Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子 ...
- Mybatis中resultMap与resultType区别
MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则是对外部ResultM ...
- 软工第三次作业——个人PSP
9.22--9.26本周例行报告 1.PSP(personal software process )个人软件过程. 类型 任务 预计时间 开始时间 结束时间 中断时间 实际用时 准备工作 学习重定向 ...
- “Hello World!”团队召开的第十二次会议
今天是我们团队“Hello World!”团队召开的第十二次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 一.会议时间 2 ...
- Pipeline组测试说明
PIPELINE组测试报告 前言:我们组与学霸系统的其他两个小组共同合作开发,组成学霸系统的团体工作.作为学霸系统的一环,我们组起到承上启下的作用,因此,面向群体以及功能实现都是为给下一个组的工作做好 ...
- BluetoothDevice详解
一. BluetoothDevice简介 1. 继承关系 public static Class BluetoothDevice extends Object implement Parcelable ...
- linux系统中如何进入退出vim编辑器的方法及区别
在linux家族中,vim编辑器是系统自带的文本编辑器,其功能强大自不必说了. 偶有小白,刚接触linux,要修改某个文本文件,不可能像WINDOWS那样操作,更有甚者,进入VI编辑器后,无法退出以致 ...