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

版权声明:本文为博主原创文章,转载请附上原博客链接。 https://blog.csdn.net/CABI_ZGX/article/details/83149084

传送门


看上去就是要到最短路,但是这题数据经过构造会卡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;
}

猜你喜欢

转载自blog.csdn.net/CABI_ZGX/article/details/83149084