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

 题目大意:

n个间谍 他们之间传送信息需要一定的时间

一个联通分量里面的间谍属于一个国家,之间的信息传递不需要时间

然后问你从一个间谍传一个信息到另一个间谍那需要最少时间 也可能传不到

联通缩点+最短路

缩点所得到的新图 可能是因为有重边或是太稠密 用邻接表容易超时

基本步骤:

1,输入去重边

2,Tarjan缩点

3,重新调整缩点后间谍之间的信息传递时间

4,最短路

注意: 图有可能不完全连通

代码及其注释:

#include<iostream>
#include<cstring>
#include<stack>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<queue>

using namespace std;

const int M=1000000002;
const int N=515;
struct node
{
    struct tt *next;
}mem[N];
struct node1
{
    struct tt *next;
}remem[N];
struct tt
{
    struct tt *next;
    int j;
};
bool in[N];
bool visited[N];
int deep;
stack<int>str;
int dfn[N];
int low[N];
int uppoint[N];
int time[N][N];
inline void build(int i,int j)
{
    struct tt *t=new tt;
    t->j=j;
    t->next=mem[i].next;
    mem[i].next=t;
}
inline void Clearlist(int n)
{
    for(int i=1;i<=n;++i)
    {
        mem[i].next=NULL;
    }
}
void Tarjan(int x)//缩点
{
    ++deep;
    dfn[x]=low[x]=deep;
    visited[x]=true;
    in[x]=true;
    str.push(x);
    struct tt *t=mem[x].next;
    while(t!=NULL)
    {
        if(visited[t->j]==false)
        {
            Tarjan(t->j);
            low[x]=min(low[x],low[t->j]);
        }else if(in[t->j]==true)
        {
            low[x]=min(low[x],dfn[t->j]);
        }
        t=t->next;
    }
    if(low[x]==dfn[x])
    {
        while(str.top()!=x)
        {
            uppoint[str.top()]=x;
            in[str.top()]=false;
            str.pop();
        }
        uppoint[str.top()]=x;
        in[str.top()]=false;
        str.pop();
    }
}
void dfs(int x)//调整缩点后有用点之间的信息传递时间
{
    visited[x]=true;
    struct tt *t=mem[x].next;
    while(t!=NULL)
    {
        if(uppoint[x]!=uppoint[t->j])
        {
            time[uppoint[x]][uppoint[t->j]]=min(time[uppoint[x]][uppoint[t->j]],time[x][t->j]);
        }
        if(!visited[t->j])
        {
            dfs(t->j);
        }
        t=t->next;
    }
}
int mintime(int st,int nd,int n)//求最短路
{
    if(st==nd)
    return 0;
    int dist[N];
    memset(visited,false,sizeof(visited));
    for(int i=1;i<=n;++i)
    if(time[st][i]==-1)
    dist[i]=M;
    else
    dist[i]=time[st][i];
    visited[st]=true;
    for(int w=1;w<n;++w)
    {
        int MIN=M;int k=-1;
        for(int i=1;i<=n;++i)
        {
            if(!visited[i]&&dist[i]<MIN)
            {
                MIN=dist[i];k=i;
            }
        }
        if(k==-1)
        break;
        if(k==nd)
        break;
        visited[k]=true;
        for(int i=1;i<=n;++i)
        {
            if(dist[i]>dist[k]+time[k][i])
            dist[i]=dist[k]+time[k][i];
        }
    }
    return dist[nd];
}
int main()
{
    int n,m,q;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
        break;
        for(int i=1;i<=n;++i)//初始化
        {
            for(int j=i;j<=n;++j)
            time[i][j]=time[j][i]=M;
        }
        while(m--)
        {
            int i,j,k;
            scanf("%d %d %d",&i,&j,&k);
            if(time[i][j]>k)//去重边
            time[i][j]=k;
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                if(time[i][j]!=M)//建原图
                build(i,j);
            }
        }
        memset(dfn,-1,sizeof(dfn));
        memset(visited,false,sizeof(visited));
        memset(in,false,sizeof(in));
        memset(uppoint,-1,sizeof(uppoint));
        while(!str.empty())
        str.pop();
        deep=0;
        for(int i=1;i<=n;++i)
        {
            if(dfn[i]==-1)//因为图有可能不完全联通
            Tarjan(i);
        }
        memset(visited,false,sizeof(visited));
        for(int i=1;i<=n;++i)
        {
            if(!visited[i])//因为图有可能不完全联通
            {
                dfs(i);
            }
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                if(i!=uppoint[i]||j!=uppoint[j])//处理一下非联通缩点之间的信息传递时间
                time[i][j]=M;
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            int i,j,k;
            scanf("%d %d",&i,&j);
            i=uppoint[i];j=uppoint[j];
            k=mintime(i,j,n);
            if(k==M)
            printf("Nao e possivel entregar a carta\n");
            else
            printf("%d\n",k);
        }
        printf("\n");
        Clearlist(n);

    }
    return 0;
}

 

posted on 2012-06-03 17:22  夜->  阅读(186)  评论(0编辑  收藏  举报