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. 一起了解 .Net Foundation 项目 No.15

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. NUnit Test Fr ...

  2. XCTF---easyjava的WriteUp

    一.题目来源     题目来源:XCTF题库安卓区easyjava     题目下载链接:下载地址 二.解题过程     1.将该apk安装进夜神模拟器中,发现有一个输入框和一个按钮,随便输入信息,点 ...

  3. js数组方法全

    js数组方法大全 一:前言          转载   作者:九夏       出处:https://www.cnblogs.com/jiuxia/ 我们在学到js中数组的时候,我们会接触到js中数组 ...

  4. nohub 将程序永久运行下去

    今天看了一遍文章,一直以为将程序制成sh脚本,通过crontab来间隔执行以为是真的不断执行,后来才发现是错误的,每隔一段时间都会执行一次,都会占用一个进程,难怪一看进程几十来个同样名字的进程在运行 ...

  5. 最简单的???ubuntu 通过crontab定时执行一个程序

    crontab在liunx系统中下载,我默认是认为下载安装了的.. crontab貌似只能在liunx系统中存在,如果是windows系统我不知道 创建一个名为jiaoben的文件夹存储sh文件,进入 ...

  6. iframe的父子层跨域 用了百度的postMessage()方法

    父层:第一个是方法申明 第二个是接收子层过来的数据 <script type="text/javascript"> $("#main").load( ...

  7. mongo密码的设置

    MongoDB 版本 v4.0.7 系统 Win10 注意: 要为数据库创建用户,必须先切换到相应的数据库: 要为数据库创建用户,必须先切换到相应的数据库: 要为数据库创建用户,必须先切换到相应的数据 ...

  8. js 数组 方法

    instanceof 检测一个对象是否是数组;(用来对付复杂数据类型;)// 简单数据类型 typeof ;A instanceof B // A是不是B造出来的;例: var arr = [1,2, ...

  9. foobox更新日志

    2020-1-31, 6.1.5.1a 版(*) 跟进汉化版修正.(*) MusicTag升级到 1.0.4.0.(*) 部分图标改良,其他优化和修正.(+) 丰富网络功能,增加一个搜索源,一个榜单源 ...

  10. python的元类编程

    廖雪峰的python教程有python元类编程示例,综合代码如下 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df ...