POJ3114 Countries in War【强连通分量】【最短路径】

题目链接:

http://poj.org/problem?id=3114


题目大意:

间谍在战争期间想要传递一份谍报回国,谍报可以在邮局之间传递,但这种传递是单向的,

并且会小号一些时间。但是如果两个邮局在同一个国家的话,那么谍报在这两个邮局之间传

递是不消耗时间的,可以立即到达。如果几个邮局发出的谍报可以通过一些路径相互到达,

那么这些邮局就属于一个国家。那么问题来了:给出一个起点和终点,问最快什么时候能够

将谍报传递到。


思路:

本题求得是有向图上的最短路。以邮局为点,从一个邮局到达另一个邮局的时间为边权,但是

这里的边权分两组:相同国家的邮局之间的边权和不同国家的邮局之间的边权。考虑到相同国

家之间的邮局直接可以相互到达。所以想到了强连通分量。可以相互达到的邮局其实就是一个

强连通分量,将原图进行缩点。那么一个强连通分量就是一个国家。

进行缩点之后,原图就变成了一个有向无环图(DAG),重新建图,然后根据输入的起点和终点,

对新图用SPFA算法求最短路径。这道题和POJ3592一样,详细参考博文:

http://blog.csdn.net/lianai911/article/details/43738299


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN = 550;
const int MAXM = MAXN*MAXN;
const int INF = 0xffffff0;

struct EdgeNode
{
    int to;
    int w;
    int next;
}Edges[MAXM],Edges1[MAXM];
int Head[MAXN],Head1[MAXN];

int low[MAXN],dfn[MAXN],belong[MAXN];
int vis[MAXN],vist[MAXN];
int Stack[MAXN];
int m,lay,scc,id,ip,N,M;
int Dist[MAXN];

void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}

void AddEdges1(int u,int v,int w)
{
    Edges1[ip].to = v;
    Edges1[ip].w = w;
    Edges1[ip].next = Head1[u];
    Head1[u] = ip++;
}

int TarBFS(int pos)
{
    int v;
    vis[pos] = 1;
    low[pos] = dfn[pos] = ++lay;
    Stack[m++] = pos;
    for(int i = Head[pos]; i != -1; i = Edges[i].next)
    {
        int v = Edges[i].to;
        if( !dfn[v] )
        {
            TarBFS(v);
            low[pos] = min(low[pos],low[v]);
        }
        else if(vis[v])
            low[pos] = min(low[pos],low[v]);
    }

    if(dfn[pos] == low[pos])
    {
        ++scc;
        do
        {
            v = Stack[--m];
            belong[v] = scc;
            vis[v] = 0;
        }while(v != pos);
    }
    return 0;
}

void ReBuildMap()
{
    for(int u = 1; u <= N; ++u)
    {
        for(int k = Head[u]; k != -1; k = Edges[k].next)
        {
            int v = Edges[k].to;
            if(belong[u] != belong[v])
                AddEdges1(belong[u],belong[v],Edges[k].w);
        }
    }
}

void SPFA(int s)
{
    memset(vist,0,sizeof(vist));
    for(int i = 0; i <= N; ++i) //不能用memset(Dist,INF,sizeof(Dist));赋值
        Dist[i] = INF;

    queue<int> Q;
    Q.push(s);
    vist[s] = 1;
    Dist[s] = 0;

    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vist[u] = 0;

        for(int i = Head1[u]; i != -1; i = Edges1[i].next)
        {
            int v = Edges1[i].to;
            if(Dist[v] > Dist[u] + Edges1[i].w)
            {
                Dist[v] = Dist[u] + Edges1[i].w;
                if( !vist[v] )
                {
                    vist[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
}

int main()
{
    int u,v,w,k;
    while(~scanf("%d%d",&N,&M) && N)
    {
        memset(Head,-1,sizeof(Head));
        memset(Head1,-1,sizeof(Head1));
        memset(vis,0,sizeof(vis));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        scc = m = lay = id = ip = 0;
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            AddEdges(u,v,w);
        }
        for(int i = 1; i <= N; ++i)
        {
            if(!dfn[i])
                TarBFS(i);
        }

        ReBuildMap();

        scanf("%d",&k);
        while(k--)
        {
            scanf("%d%d",&u,&v);
            if(belong[u]==belong[v])
                printf("0\n");
            else
            {
                SPFA(belong[u]);
                if(Dist[belong[v]] != INF)
                    printf("%d\n",Dist[belong[v]]);
                else
                    printf("Nao e possivel entregar a carta\n");
            }
        }
        printf("\n");
    }

    return 0;
}


你可能感兴趣的:(POJ3114 Countries in War【强连通分量】【最短路径】)