Delivery Route

题目:有n个派送点,x条双向边,y条单向边,出发点是s,双向边的权值均为正,单向边的权值可以为负数,对于单向边给出了一个限制:如果u->v成立,则v->u一定不成立。问,从s出发,到其他所有点的最短路是多少(包括s)。

思路:对于单向边的限制,我们可以这么理解:双向边相连接的点一定组成一个强连通分量,如果一条单向边存在于某个强连通分量中,可以得出:如果“u -> v”,则一定“v -> u”,可以推出单向边一定只存在于连接两个强连通分量,且还可以推出,强连通分量缩点后,连上单向边,此时的图一定是一个有向无环图,于是给出的限制"对于单向边给出了一个限制:如果u->v成立,则v->u一定不成立。"完全成立,于是图的性质我们分析完了。

①似乎这个图的性质可以直接跑dijkstra,的确可以,但是负权边的存在复杂度太大。

②每个强连通分量都可以dijkstra,且图存在拓扑排序,不如让入度为0的缩点先跑dijkstra,然后一条单向边只影响其他强连通分量的一个点的距离,然后按照拓扑序来确定每个强连通分量跑dijkstra的顺序。

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue> #define ll long long
#define pb push_back
#define fi first
#define se second using namespace std; const int N = + ;
const int M = + ;
const ll INF = 1e10;
struct Edge{
int to, nxt, w;
}e[M << ];
struct node{
int u, v, w;
};
struct tmp{
int now;
ll w;
bool friend operator<(const tmp& a, const tmp& b){
return a.w > b.w;
}
};
int head[N], scc[N], du[N], vis[N], ok[N];
ll dis[N];
vector<node > vp[N];//单向边
vector<int > belong[N];//属于哪个scc
vector<int > mp[N];//存边
priority_queue<tmp > pque;
int n, x, y, s, tot, col; inline void add(int u, int v, int w){
e[tot].to = v; e[tot].nxt = head[u];
e[tot].w = w; head[u] = tot++;
} //缩点
void dfs(int now){
scc[now] = col;
belong[col].pb(now);
for(int o = head[now]; ~o; o = e[o].nxt)
if(!scc[e[o].to]) dfs(e[o].to);
} //检测这个点是不是有效点
void check(int now){
ok[now] = ;
for(auto to : mp[now])
if(!ok[to]) check(to);
} void dijkstra(int ss){
while(!pque.empty()) pque.pop();
if(ss == s) pque.push({ss, dis[ss]}); //图一定是从出发点s开始的
else{
//相当于从一个超级源点出发
for(auto it : belong[scc[ss]]) pque.push({it, dis[it]});
}
while(!pque.empty()){
int u = pque.top().now;
pque.pop();
if(vis[u]) continue;
vis[u] = ;
for(int o = head[u]; ~o; o = e[o].nxt){
if(dis[u] + e[o].w < dis[e[o].to]){
dis[e[o].to] = dis[u] + e[o].w;
pque.push({e[o].to, dis[e[o].to]});
}
}
}
} void top_sort(){
queue<int > que;
que.push(scc[s]);//满足的图 应该是从s的连通图出发的拓扑图
dijkstra(s);
while(!que.empty()){
int inx = que.front();
que.pop();
for(auto it : vp[inx]){
//一条单向边影响一个点的距离
if(dis[it.u] + it.w < dis[it.v]){
dis[it.v] = dis[it.u] + it.w;
}
//入度0,跑dijkstra
if(--du[scc[it.v]] == ){
que.push(scc[it.v]);
dijkstra(it.v);
}
}
}
} void solve(){
scanf("%d%d%d%d", &n, &x, &y, &s);
for(int i = ; i <= n; ++i) head[i] = -; tot = ;
for(int i = ; i <= n; ++i) dis[i] = INF; dis[s] = ;
int u, v, w;
for(int i = ; i <= x; ++i){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
mp[u].pb(v); mp[v].pb(u);
} vector<node > tmp;
for(int i = ; i <= y; ++i){
scanf("%d%d%d", &u, &v, &w);
tmp.pb({u, v, w});
mp[u].pb(v);
}
//图一定是从出发点s开始的,所以从s出发遍历图,无法到达的点,就是无法到达的点
//检测这个点是不是有效点
check(s);
//缩点
for(int i = ; i <= n; ++i){
if(!scc[i] && ok[i]){
++col;
dfs(i);
}
}
//入度统计
for(auto x : tmp){
if(ok[x.u] && ok[x.v]){//有效点
vp[scc[x.u]].pb(x);
++du[scc[x.v]];
}
}
top_sort();//拓扑序
for(int i = ; i <= n; ++i){
if(dis[i] == INF) printf("NO PATH\n");
else printf("%lld\n", dis[i]);
}
} int main(){ solve(); return ;
} /*
7 5 3 4
1 2 5
3 4 5
5 6 10
5 7 4
6 7 105
3 5 -100
4 6 -100
7 2 -100
*/

 

2019ICPC(银川) - Delivery Route(强连通分量 + 拓扑排序 + dijkstra)的更多相关文章

  1. BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP

    BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP Description In an effort to better manage t ...

  2. BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset

    BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i ...

  3. poj 2762(强连通分量+拓扑排序)

    题目链接:http://poj.org/problem?id=2762 题意:给出一个有向图,判断任意的两个顶点(u,v)能否从u到达v,或v到达u,即单连通,输出Yes或No. 分析:对于同一个强连 ...

  4. BZOJ1924:[SDOI2010]所驼门王的宝藏(强连通分量,拓扑排序)

    Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室 ...

  5. CDOJ 图论专题 A.不是图论 强连通分量+拓扑排序 经典

    题目链接  在其中纠错第一次wa代码 #include <cstdio> #include <cstring> #include <cstdlib> #includ ...

  6. POJ 2762 Going from u to v or from v to u?(强连通分量+拓扑排序)

    职务地址:id=2762">POJ 2762 先缩小点.进而推断网络拓扑结构是否每个号码1(排序我是想不出来这点的. .. ).由于假如有一层为2的话,那么从此之后这两个岔路的点就不可 ...

  7. hihoCoder #1185 : 连通性·三(强联通分量+拓扑排序)

    #1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出 ...

  8. POJ-2762-Going from u to v or from v to u(强连通, 拓扑排序)

    链接: https://vjudge.net/problem/POJ-2762 题意: In order to make their sons brave, Jiajia and Wind take ...

  9. poj 2186 "Popular Cows"(强连通分量入门题)

    传送门 参考资料: [1]:挑战程序设计竞赛 题意: 每头牛都想成为牛群中的红人. 给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人: 该关系具有传递性,所以如果牛A认为牛 ...

随机推荐

  1. JS数组遍历方法集合

    就让我们在逆战中成长吧,加油武汉,加油自己 1.for循环 使用零时变量将长度存起来,当数组较大时优化效果才会比较明显. var ar1=[2,4,6,8] for(var i=0;i<ar1. ...

  2. Ubuntu 16 编译装python2.7

    Ubuntu 16自带 python3 ,有很多库无法使用,决定装 python2.7 试了试,好像 apt-get 装不上. 使用源码,编译安装. wget https://www.python.o ...

  3. Java自学路线图之Java系统自学

    Java自学不是一朝一夕的事情.可以采用"懒开始"的方法,但是必须要坚持下去,才能真正自学Java掌握编程技术.那些企图学几天去包装一下找工作的,请绕道.如果你下定决心自学Java ...

  4. 第16个算法 - leetcode-二叉树的层次遍历

    二叉树的层次遍历 参考:https://www.cnblogs.com/patatoforsyj/p/9496127.html 给定一个二叉树,返回其按层次遍历的节点值. (即逐层地,从左到右访问所有 ...

  5. Wireshark过滤器写法总结

    目录 #Wireshark提供了两种过滤器: 1.捕获过滤器 2.显示过滤器 #过滤器具体写法 #显示过滤器写法 #捕捉过滤器写法 #Wireshark提供了两种过滤器: 1.捕获过滤器 捕获过滤器: ...

  6. WPF转换器之值转换器

    WPF有两转转换器,一种是值转换器,另一种多值转换器,在开发过程中经常会从数据拉一些数据过来,比如存储性别的时候往往会用0或1,但在界面上肯定是要显示男或女,那么这个时候就可以用上值转换器 编写转换器 ...

  7. webStorm ctrl+L 跳转到指定行line eclipes快捷键

    webStorm ctrl+L 跳转到指定行line eclipes快捷键

  8. 靓仔,整合SpringBoot还在百度搜配置吗?老司机教你一招!!!

    导读 最近陈某公司有些忙,为了保证文章的高质量可能要两天一更了,在这里陈某先说声不好意思了!!! 昨天有朋友问我SpringBoot如何整合Redis,他说百度谷歌搜索了一遍感觉不太靠谱.我顿时惊呆了 ...

  9. HTML每日学习笔记(2)

    7.16.2019 1.html表单:用于得到用户不同类型的输入 <form>元素定义表单: <form> First name:<br> <input ty ...

  10. 推荐两款好用的JS格式化工具

    工具一: 直接在Chrome浏览器中,F12,打开Sources栏,找到JS文件,点击下面的花括号即可. 工具二: 使用notepad++ 格式化JS文件. 1.下载 jstool 插件(https: ...