pku 3114 Countries in War tarjan缩点+spfa求最短路

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

/*

这道题和3592非常类似,所以做了那道题后再做这道就有感觉了,自己写的而且1Y好开心的样子,哈哈.....

题意:战争期间国家之间的通信,给定n个城市,m个城市之间的可传输协议。如果若干个城市强连通则说明他们属于同一个国家股他们之间的通信可立即到达,消耗时间为0,否则就要消耗指定的时间h了。给定k个询问x,y问由x到y的最小耗费时间。

思路:首先根据给定m个协议,构建图,然后求强连通分量缩点,将缩点后的图,重新建立,如果属于同一国家他们之间的权值就变为0,不属于同于国家权值仍为h。然后就是spfa求最短路了;

*/

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define maxn 507
using namespace std;

const int inf = 99999999;

struct node
{
    int v,w;
    int next;
}g[maxn*maxn],e[maxn*maxn];

int cnt,head[maxn];
int dfn[maxn],low[maxn],belong[maxn];
int stack[maxn],index,top,bcnt;
bool ins[maxn],inq[maxn];
int dis[maxn];
int n,m,k;
int hash[maxn];
int HD[maxn],ct;

void add(int u,int v,int w)
{
    g[cnt].v = v;
    g[cnt].w = w;
    g[cnt].next = head[u];
    head[u] = cnt++;
}
void addEG(int u,int v,int w)
{
    e[ct].v = v;
    e[ct].w = w;
    e[ct].next = HD[u];
    HD[u] = ct++;
}
void initT()
{
    int i;
    bcnt = top = index = 0;
    for (i = 0; i < maxn; ++i)
    {
        dfn[i] = low[i] = 0;
        belong[i] = 0;
        ins[i] = false;
    }
}
void tarjan(int i)
{
    int ki,j;
    dfn[i] = low[i] = ++index;
    stack[++top] = i;
    ins[i] = true;
    for (ki = head[i]; ki != -1; ki = g[ki].next)
    {
        j = g[ki].v;
        if (!dfn[j])
        {
            tarjan(j);
            low[i] = min(low[i],low[j]);
        }
        else if (ins[j])
        {
            low[i] = min(low[i],dfn[j]);
        }
    }
    if (dfn[i] == low[i])
    {
        bcnt++;
        do
        {
            j = stack[top--];
            ins[j] = false;
            belong[j] = bcnt;
        }while (j != i);
    }
}
void solve()
{
    int i;
    //缩点
    initT();
    for (i = 1; i <= n; ++i)
    {
        if (!dfn[i]) tarjan(i);
    }
    /*printf("*********\n");
    for (i = 1; i <= n; ++i)
    printf("%d ",belong[i]);
    printf("\n");*/
}
void spfa(int s)
{
    int i;
    queue<int>q;
    for (i = 0; i < maxn; ++i)
    {
        dis[i] = inf;
        inq[i] = false;
    }
    q.push(s); inq[s] = true;
    dis[s] = 0;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        inq[u] = false;
        for (i = HD[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w)
            {
                dis[v] = dis[u] + e[i].w;
                if (!inq[v])
                {
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int i,j,x,y,h,ki;
    while (~scanf("%d",&n))
    {
        scanf("%d",&m);
        if (!n) break;
//根据协议建图
        memset(head,-1,sizeof(head));
        cnt = 0;
        for (i = 0; i < m; ++i)
        {
            scanf("%d%d%d",&x,&y,&h);
            add(x,y,h);
        }

        solve();
//缩点后建图
        memset(HD,-1,sizeof(HD));
        ct = 0;
        for (i = 1; i <= n; ++i)
        {
            for (ki = head[i]; ki != -1; ki = g[ki].next)
            {
                j = g[ki].v;
                if (belong[i] == belong[j]) addEG(i,j,0);//属于同一个国家权值为0
                else addEG(i,j,g[ki].w);//否则权值为h不变
            }
        }
        /*for (i = 1; i <= n; ++i)
        {
            printf("LLL>%d:   ",i);
            for (ki = head[i]; ki != -1; ki = g[ki].next)
            {
                printf("%d ",g[ki].v);
            }
            printf("\n");
        }*/
//spfa求最短路了
        scanf("%d",&k);
        for (i = 0; i < k; ++i)
        {
            scanf("%d%d",&x,&y);
            spfa(x);
            if (dis[y] != inf)
            printf("%d\n",dis[y]);
            else
            printf("Nao e possivel entregar a carta\n");
        }
        printf("\n");
    }
    return 0;
}

  

posted @ 2012-06-30 17:04  E_star  阅读(299)  评论(0编辑  收藏  举报