2019ICPC(银川) - Delivery Route(强连通分量 + 拓扑排序 + dijkstra)
题目:有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)的更多相关文章
- BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP
		
BZOJ_3887_[Usaco2015 Jan]Grass Cownoisseur_强连通分量+拓扑排序+DP Description In an effort to better manage t ...
 - BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset
		
BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i ...
 - poj 2762(强连通分量+拓扑排序)
		
题目链接:http://poj.org/problem?id=2762 题意:给出一个有向图,判断任意的两个顶点(u,v)能否从u到达v,或v到达u,即单连通,输出Yes或No. 分析:对于同一个强连 ...
 - BZOJ1924:[SDOI2010]所驼门王的宝藏(强连通分量,拓扑排序)
		
Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室 ...
 - CDOJ   图论专题   A.不是图论   强连通分量+拓扑排序     经典
		
题目链接 在其中纠错第一次wa代码 #include <cstdio> #include <cstring> #include <cstdlib> #includ ...
 - POJ 2762 Going from u to v or from v to u?(强连通分量+拓扑排序)
		
职务地址:id=2762">POJ 2762 先缩小点.进而推断网络拓扑结构是否每个号码1(排序我是想不出来这点的. .. ).由于假如有一层为2的话,那么从此之后这两个岔路的点就不可 ...
 - hihoCoder  #1185 : 连通性·三(强联通分量+拓扑排序)
		
#1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出 ...
 - 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 ...
 - poj 2186 "Popular Cows"(强连通分量入门题)
		
传送门 参考资料: [1]:挑战程序设计竞赛 题意: 每头牛都想成为牛群中的红人. 给定N头牛的牛群和M个有序对(A, B),(A, B)表示牛A认为牛B是红人: 该关系具有传递性,所以如果牛A认为牛 ...
 
随机推荐
- vue+element 表单封成组件(1)
			
作为一名刚接触vue不到一个月的菜鸟,思想还没有从操作DOM转变为数据驱动,看vue的代码处处别扭.组里为了让我熟悉vue交给了我一个将element 表单封装成组件的练手任务.由于开发过程中遇到的表 ...
 - JAVA Integer值的范围
			
原文出处:http://hi.baidu.com/eduask%C9%BD%C8%AA/blog/item/227bf4d81c71ebf538012f53.html package com.test ...
 - volatile关键字的理解
			
volatile是java语言提供的一种稍弱的同步机制,它的作用是能够保证被volatile修饰的变量,每个线程在获取它的值时都能获取到最新的值. 要理解这个原理首先要知道java内存模型:每个线程都 ...
 - 学以致用:手把手教你撸一个工具库并打包发布,顺便解决JS浮点数计算精度问题
			
本文讲解的是怎么实现一个工具库并打包发布到npm给大家使用.本文实现的工具是一个分数计算器,大家考虑如下情况: \[ \sqrt{(((\frac{1}{3}+3.5)*\frac{2}{9}-\fr ...
 - Js逆向-滑动验证码图片还原
			
本文列举两个例子:某象和某验的滑动验证 一.某验:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby9zbGlkZS1mbG9hdC5odG1s 未还原图像: 还原后的图: ...
 - TCP数据报结构以及三次握手(图解)
			
简要介绍 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的.可靠的.基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接.客户端在收发 ...
 - .net webapi 接收保存图片到服务器,并居中剪裁压缩图片
			
原文链接:https:////www.cnblogs.com/Jackyye/p/12510943.html 每天解决一些c#小问题,在写微信小程序,或者一些手机软件接口,我们经常要用到上传图片到服务 ...
 - watch 同步表单 记得$nextTick,否则不会同步更新到组件内
			
watch 同步表单 记得$nextTick,否则不会同步更新到组件内 watch: { 'formData.aaa' (val) { this.$nextTick(() => { this.f ...
 - 配置GitLab或Git环境之教程
			
配置GitLab或Git环境之教程 1.安装好Git后,首先打开开始菜单的所有程序里面的git文件夹,打开Git Bash/  2.弹出的命令行里面输入ssh-keygen 输入y,一直Enter ...
 - iOS开发:Swift/Objective-C高效生成随机字符串
			
原文连接 Objective-C版 // 随机生成字符串(由大小写字母.数字组成) + (NSString *)random: (int)len { char ch[len]; for (int in ...