• 【BZOJ2200】道路与航线


    题目链接:https://www.acwing.com/problem/content/344/

    题目大意:给定一张有向图 , 其中可分为若干个连通块 , 每个连通块内的道路均为双向 , 且权值为正 , 联通块间的道路为单向 , 权值可为负数 , 这若干个连通块组成一个DAG , 求起点 (s) 到各个节点的最短路径

    solution

    显然这是一个单元最短路模板 , 但边权有为负 , 用SPFA会被卡掉 , 但可以利用题目中的一些性质来解决

    对于每个连通块内 , 可以用dijstra来求出点之间的最短路径 , 连通块之间由于构成了一个DAG , 可以用拓扑来求最短路径

    具体地 , 可以构建一个队列 , 每次加入总入度为 0 的联通块 , 每次取出队首的连通块 , 在块内跑dijstra , 与此同时把这个连通块所相邻的各个连通块的总入度减去 1 , 若发现入度减为 0 , 则把这个连通块入队

    复杂度 : (O(mlogn))

    code

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T> inline void read(T &FF) {
    	int RR = 1; FF = 0; char CH = getchar();
    	for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    	for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    	FF *= RR;
    }
    inline void file(string str) {
    	freopen((str + ".in").c_str(), "r", stdin);
    	freopen((str + ".out").c_str(), "w", stdout);
    }
    const int N = 5e5 + 10;
    int si, now, vis[N], fst[N], nxt[N], num[N], wi[N], n, x, y, s, rd[N];
    void add(int u, int v, int w) {
    	nxt[++now] = fst[u], fst[u] = now, num[now] = v, wi[now] = w;
    }
    void dfs(int xi) {
    	for(int i = fst[xi]; i; i = nxt[i])
    		if(!vis[num[i]])
    			vis[num[i]] = vis[xi], dfs(num[i]);
    }
    int st[N], bk[N]; queue<int> q;
    void dijstra(int xi) {
    	priority_queue<pair<int, int> > qi;
    	for(int i = 1; i <= n; i++)
    		if(vis[i] == xi)
    			qi.push(make_pair(-st[i], i));
    	while(!qi.empty()) {
    		int pi = qi.top().second; qi.pop();
    		if(bk[pi]) continue; bk[pi] = true;
    		for(int i = fst[pi]; i; i = nxt[i]) {
    			if(st[pi] + wi[i] < st[num[i]]) {
    				st[num[i]] = st[pi] + wi[i];
    				if(vis[pi] == vis[num[i]])
    					qi.push(make_pair(-st[num[i]], num[i]));
    			}
    			if(vis[pi] != vis[num[i]]) {
    				rd[vis[num[i]]]--;
    				if(!rd[vis[num[i]]]) q.push(vis[num[i]]);
    			}
    		}
    	}
    }
    int main() {
    	//file("");
    	int u, v, w;
    	read(n), read(x), read(y), read(s);
    	for(int i = 1; i <= x; i++)
    		read(u), read(v), read(w), add(u, v, w), add(v, u, w);
    	for(int i = 1; i <= n; i++)
    		if(!vis[i]) vis[i] = ++si, dfs(i);
    	for(int i = 1; i <= y; i++) {
    		read(u), read(v), read(w), add(u, v, w);
    		rd[vis[v]]++;
    	}
    	memset(st, 0x3f, sizeof(st)); st[s] = 0;
    	for(int i = 1; i <= si; i++)
    		if(rd[i] == 0) q.push(i);
    	//if(rd[vis[s]]) q.push(vis[s]);
    	while(!q.empty()) {
    		int pi = q.front(); q.pop();
    		dijstra(pi);
    	}
    	for(int i = 1; i <= n; i++)
    		if(st[i] >= 1e9) puts("NO PATH");
    		else cout << st[i] << endl;
    	return 0;
    }
    
  • 相关阅读:
    [生活] 日常英语学习笔记-NEVER HAVE I EVER游戏
    [PHP] 网盘搜索引擎-采集爬取百度网盘分享文件实现网盘搜索(二)
    [PHP] 网盘搜索引擎-采集爬取百度网盘分享文件实现网盘搜索
    [Linux] PHP程序员玩转Linux系列-telnet轻松使用邮箱
    [Linux] PHP程序员玩转Linux系列-升级PHP到PHP7
    [Linux] PHP程序员玩转Linux系列-使用supervisor实现守护进程
    [Linux] PHP程序员玩转Linux系列-Nginx中的HTTPS
    [Linux] PHP程序员玩转Linux系列-nginx初学者引导
    [Linux] PHP程序员玩转Linux系列-Linux和Windows安装nginx
    [Linux] PHP程序员玩转Linux系列-自动备份与SVN
  • 原文地址:https://www.cnblogs.com/magicduck/p/12240858.html
Copyright © 2020-2023  润新知