洛谷3008 [USACO11JAN]道路与航线(Dijkstra)(拓扑序)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/82896215

题目

洛谷3008 [USACO11JAN]道路和飞机Roads and Planes

题解

Dijkstra+拓扑排序+乱搞
省选题怎么可能考裸的SPFA?
题目中有一句话改变了这题的最优解法:“如果有一条航线可以从A_i到B_i,那么保证不可能通过一些道路和航线从B_i回到A_i。”
它不仅告诉我们没有负环,还说明可以用拓扑序,还说这张图就是几个大的用单向边连接的连通块。
所以我们的决策是,块内dijkstra,块外拓扑序处理。
接下来就是乱码一通了。

代码

这个是把拓扑与dij分开实现的:
 

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int maxn=25010,maxm=100010;

int t,r,p,s;

struct E{int y,c,next;bool v;}e[maxm*2];int len=0,last[maxn];
void ins(int x,int y,int c,bool v)
{
    e[++len]=(E){y,c,last[x],v};last[x]=len;
}

vector<int> fir[maxn];
int tot=0,dep[maxn],in[maxn];
struct O{int y,next;}h[maxm*2];int ool=0,ola[maxn];
void add(int x,int y)
{
    h[++ool]=(O){y,ola[x]};ola[x]=ool;
    in[y]++;
}
void dfs(int x)
{
    for(int k=last[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(dep[y]!=0 && dep[y]!=dep[x]) fir[dep[y]].push_back(y),add(dep[x],dep[y]);
        if(dep[y]) continue;
        if(e[k].v) dep[y]=++tot,fir[dep[y]].push_back(y),add(dep[x],dep[y]);
        else dep[y]=dep[x];
        dfs(y);
    }
}

int d[maxn];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra(int sstt)
{
    for(int i=0;i<fir[sstt].size();i++)//把这块中的点放进来,用vector实现 
    {
        int x=fir[sstt][i];
        q.push(make_pair(d[x],x));
    }
    while(!q.empty())
    {
        int dis=q.top().first,x=q.top().second;q.pop();
        while(!q.empty() && dis>d[x]) dis=q.top().first,x=q.top().second,q.pop();
        if(q.empty() && dis>d[x]) break;
        for(int k=last[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(d[y]>d[x]+e[k].c)
            {
                d[y]=d[x]+e[k].c;
                if(dep[y]==sstt) q.push(make_pair(d[y],y));//debug 每次只是同块间做dij,不能跨块 
            }
        }
    }
}

int main()
{
    scanf("%d%d%d%d",&t,&r,&p,&s);
    for(int i=1;i<=r;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c,0);ins(y,x,c,0);
    }
    for(int i=1;i<=p;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);//debug %d
        ins(x,y,c,1);
    }
    
    fir[1].push_back(s);
    dep[s]=++tot;dfs(s);
    
    queue<int> qq;
    qq.push(1);
    memset(d,63,sizeof(d));d[s]=0;
    for(int i=1;i<=tot;i++)
    {
        int x=qq.front();qq.pop();
        dijkstra(x);
        for(int k=ola[x];k;k=h[k].next)
        {
            int y=h[k].y;
            in[y]--;
            if(in[y]==0) qq.push(y);
        }
    }
    
    for(int i=1;i<=t;i++)
        if(dep[i]==0) puts("NO PATH");
        else printf("%d\n",d[i]);
    return 0;
}

这个是两者合在一起实现的:

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int maxn=25010,maxm=100010;

int t,r,p,s;

struct E{int y,c,next;bool v;}e[maxm*2];int len=0,last[maxn];
void ins(int x,int y,int c,bool v)
{
    e[++len]=(E){y,c,last[x],v};last[x]=len;
}

struct O{int x,next;}h[maxn];int ool=0,ola[maxn];
void add(int x,int y)//把x加入y集合 
{
    h[++ool]=(O){x,ola[y]};ola[y]=ool;
}
int tot=0,dep[maxn],in[maxn];
void dfs(int x)
{
    add(x,dep[x]);
    for(int k=last[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(dep[y]!=0 && dep[y]!=dep[x]) in[dep[y]]++;
        if(dep[y]) continue;
        if(e[k].v) dep[y]=++tot,in[dep[y]]++;
        else dep[y]=dep[x];
        dfs(y);
    }
}

int d[maxn];bool vis[maxn];
int list[maxn];int head,tail;
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra(int sstt)
{
    head=0;tail=0;
    list[0]=1;
    while(head<=tail)
    {
        int u=list[head++];
        for(int k=ola[u];k;k=h[k].next) q.push(make_pair(d[h[k].x],h[k].x));
        while(!q.empty())
        {
            int x=q.top().second;q.pop();
            if(vis[x]) continue;
            vis[x]=true;
            for(int k=last[x];k;k=e[k].next)
            {
                int y=e[k].y;
                if(dep[y]!=dep[x])
                {
                    in[dep[y]]--;
                    if(in[dep[y]]==0) list[++tail]=dep[y];
                }
                if(d[y]>d[x]+e[k].c)
                {
                    d[y]=d[x]+e[k].c;
                    if(dep[x]==dep[y]) q.push(make_pair(d[y],y));
                }
            }
        }
    }
    
}

int main()
{
    scanf("%d%d%d%d",&t,&r,&p,&s);
    for(int i=1;i<=r;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c,0);ins(y,x,c,0);
    }
    for(int i=1;i<=p;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c,1);
    }
    
    dep[s]=++tot;dfs(s);
    
    memset(d,63,sizeof(d));d[s]=0;
    dijkstra(s);
    
    for(int i=1;i<=t;i++)
        if(dep[i]==0) puts("NO PATH");
        else printf("%d\n",d[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/82896215