1. 程式人生 > >[BZOJ2200][Usaco2011 Jan]道路和航線(拓撲排序+Dijkstra)

[BZOJ2200][Usaco2011 Jan]道路和航線(拓撲排序+Dijkstra)

傳送門


看上去就是要到最短路,但是這題資料經過構造會卡SPFA(大家都嫌棄他嚶嚶,but可以用SLF優化水過),且因為有負權會卡Dijkstra。

那麼我們觀察題意,發現只有單向邊是有負權的,雙向邊沒有負權,且單向邊不會構成環!那麼我們就可以把原圖看作許多個由雙向邊組成的連通塊,連通塊由單向邊互相連在一起形成一個DAG圖,對於DAG圖 我們就可以用拓撲序線上性時間內遍歷求出答案,對於連通塊內的最短路資訊因為雙向邊沒有負權可以用Dijkstra直接處理。

那麼實現的話首先就可以先把雙向邊連起來,用dfs求出連通塊,在拓撲排序遍歷連通塊的大框架下對於每一個連通塊內的跑Dij即可。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=3e5+10,M=3e5+10;
const int INF=0x7f7f7f7f;
inline int read()
{
	int x=0,f=1; char
ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct edge { int x,y,c,next; }a[N]; int len,last[N]; void ins(int x,int y,int c) { a[++len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[
x];last[x]=len; } bool v[N]; int cnt; vector<int> has[N]; int bl[N]; void dfs(int x) { v[x]=1; has[cnt].push_back(x); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(!v[y])bl[y]=bl[x],dfs(y); } } struct node { int d,id; bool operator <(const node &b) const { return d>b.d; } }; priority_queue<pair<int,int> > q; int deg[N]; int n,R,P,st; int list[M],head,tail; int dis[N]; int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); n=read(); R=read(); P=read(); st=read(); len=0; memset(last,0,sizeof(last)); for(int i=1;i<=R;i++) { int x=read(),y=read(),c=read(); ins(x,y,c); ins(y,x,c); } //get scc cnt=0; memset(bl,0,sizeof(bl)); memset(v,0,sizeof(v)); for(int i=1;i<=n;i++) if(!v[i]) { cnt++; bl[i]=cnt; dfs(i); } //rebuild to DAG memset(deg,0,sizeof(deg)); for(int i=1;i<=P;i++) { int x=read(),y=read(),c=read(); ins(x,y,c); ins(bl[x]+n,bl[y]+n,c); } //Get deg head=1,tail=1; list[1]=bl[st]+n; memset(v,0,sizeof(v)); while(head<=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(!v[y])v[y]=1,list[++tail]=y; deg[y-n]++; } head++; } //Dij+Topsort memset(dis,0x7f,sizeof(dis)); dis[st]=0; memset(v,0,sizeof(v)); head=1,tail=1; list[1]=bl[st]; while(head<=tail) { int cc=list[head]; // for(int i=1;i<=n;i++)if(bl[i]==cc)q.push(make_pair(-dis[i],i)); int siz=has[cc].size(); for(int i=0;i<siz;i++) q.push(make_pair(-dis[has[cc][i]],has[cc][i])); while(q.size()) { int x=q.top().second;q.pop(); if(v[x])continue; v[x]=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(bl[x]!=bl[y]){deg[bl[y]]--; if(deg[bl[y]]==0)list[++tail]=bl[y];} if(dis[y]>dis[x]+a[k].c) { dis[y]=dis[x]+a[k].c; if(bl[x]==bl[y])q.push(make_pair(-dis[y],y)); } } } head++; } for(int i=1;i<=n;i++) { if(dis[i]==INF) puts("NO PATH"); else printf("%d\n",dis[i]); } return 0; }