poj 3114 Countries in War

强连通分量 + 最短路

题意:城市间通信,给出n,n个城市,m,m条边,分别是端点和权,如果两个城市属于同一个国家,那么他们的通信时间为0,否则则按边权算一次的通信时间。两个城市被认为在一个国家,是从A能到B,从B也能到A。下面给出K个查询,能从u到v传递信息,需要多少时间,如果从u无法传递到v,输出那个长长的英文句子

 

其实就是一个最短路,但是最短路的边权有讲究,虽然给出了u,v,w,但是u和v可能是同一个国家的,那么w应该是0而不是原来的值,所以要怎么判断u和v是不是在同一个国家,也就是他们可以互达,很明显不能查询一次判断一次,而是应该先搞出强连通分量,属于同一个强连通分量的两点间的边权为0

 

这题不难,很直白,tarjan,和各种最短路的算法老实打就是了

//强连通分量+最短路
//属于一个强连通分量的点,路径为0,否则按原边权

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 510
#define M 250010
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

int n,tot;
int head[N];
struct edge
{
    int u,v,w,next;
}e[M];
int dfn[N] , low[N] , belong[N] , dcnt , bcnt;
int stack[N] , top;
bool ins[N];
int d[N][N];
bool solve[N];

void add(int u ,int v ,int w ,int k)
{
    e[k].u = u; e[k].v = v; e[k].w = w;
    e[k].next = head[u]; head[u] = k;
}

void tarjan(int u)
{
    stack[++top] = u;
    ins[u] = true;
    dfn[u] = low[u] = ++dcnt;
    for(int k=head[u]; k!=-1; k=e[k].next)
    {
        int v = e[k].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u] , low[v]);
        }
        else if(ins[v])
            low[u] = min(low[u] , dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ++bcnt;
        while(1)
        {
            int x = stack[top--];
            ins[x] = false;
            belong[x] = bcnt;
            if(x == u) break;
        }
    }
}

void SCC()
{
    dcnt = bcnt = top = 0;
    memset(dfn,0,sizeof(dfn));
    memset(ins,false,sizeof(ins));
    for(int i=1; i<=n; i++)
        if(!dfn[i])
            tarjan(i);
}

void SPFA(int s)
{
    bool inq[N];
    queue<int>q;
    for(int i=0; i<=n; i++) 
    {
        d[s][i] = INF;
        inq[i] = false;
    }
    while(!q.empty()) q.pop();
    d[s][s] = 0;
    inq[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        inq[u] = false;
        for(int k=head[u]; k!=-1; k=e[k].next)
        {
            int v = e[k].v;
            int w = e[k].w;
            if(belong[u] == belong[v]) w = 0;//同一个连通分量,权为0
            if(d[s][u] + w < d[s][v])
            {
                d[s][v] = d[s][u] + w;
                if(!inq[v])
                {
                    inq[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d%d",&n,&tot)!=EOF && n)
    {
        memset(head,-1,sizeof(head));
        for(int i=0; i<tot; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w,i);
        }
        SCC();
        int K;
        scanf("%d",&K);
        memset(solve,false,sizeof(solve));
        for(int k=0; k<K; k++)
        {
            int s,t;
            scanf("%d%d",&s,&t);
            if(!solve[s])
            {
                solve[s] = true;
                SPFA(s);
            }
            if(d[s][t] == INF) printf("Nao e possivel entregar a carta\n");
            else               printf("%d\n",d[s][t]);
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2013-05-09 22:27  Titanium  阅读(301)  评论(0编辑  收藏  举报