POJ 3268 Silver Cow Party(最短路径dijkstra算法)

题目大意:

有限输入的数据N,M,X。N表示有N个农场,每个农场有一头奶牛;M表示连接这N个农场的M条边(有向边),X表示农场的一个编号(1,2,...,n)。

现在每个农场的牛都要走到编号为X的农场上去(选择最短路走),并返回自己的农场(选择最短路走),要求输出这些n头牛走的路程中(去+回的路程和)的最大值。

解题思路:

一个很简单的最短路径问题,用两次dijkstra算法就可以了,还要用到了矩阵的转置。首先用一次dijkstra算法(求编号为X的农场到其他农场的最短距离),求出每个农场的牛到X农场的最短距离。然后将矩阵(保存有向路径的信息)转置,在用一次dijkstra算法(求编号为X的农场到其他农场的最短距离),也就是求出了每头牛返回自己农场的最短距离。

如果不进行矩阵的转置,对于没有牛都用到一次dijkstra算法,那么时间复杂度就会增加,会出现超时。所以,在求每头牛返回的最短路径中,进行一次矩阵的转置,是把所有的有向边改变方向,只需一次dijkstra算法就可以了。

代码:

#include<cstdio>
#include<cstring>
#define Max 100000
#define M 1005
int time[M],a[M][M],dis[M],vis[M];
int n,m,x;
void dijkstra(int v){
    int i,j,u;
    for(int i=0;i<n;i++){
        dis[i]=a[v][i];
        vis[i]=0;
    }
    int min;
    vis[v]=1;
    for(i=1;i<n;i++){
        min=Max;u=-1;
        for(j=0;j<n;j++){
            if(vis[j]==0 && dis[j]<min){
                u=j;min=dis[j];
            }
        }
        vis[u]=1;
        for(j=0;j<n;j++){
            if(vis[j]==0 && dis[j]>dis[u]+a[u][j]){
                dis[j]=dis[u]+a[u][j];
            }
        }
    }
    return ;
}

int main(){
    int f,t,c;
    while(~scanf("%d%d%d",&n,&m,&x)){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(i==j){
                    a[i][j]=0;
                    continue;
                }
                a[i][j]=Max;
            }
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&f,&t,&c);
            a[f-1][t-1]=c;
        }
        //memset(vis,0,sizeof(vis));
        memset(time,0,sizeof(time));
        dijkstra(x-1);

        for(int i=0;i<n;i++){   //去时的最短时间
            time[i]=dis[i];
        }

        for(int i=0;i<n;i++){   //矩阵转置
            for(int j=i+1;j<n;j++){
                int tmp;
                tmp=a[i][j];
                a[i][j]=a[j][i];
                a[j][i]=tmp;
            }
        }
        dijkstra(x-1);
        for(int i=0;i<n;i++){   //返回时的最短时间
            time[i]+=dis[i];
        }
        int max=0;
        for(int i=0;i<n;i++){
            if(max<time[i])
                max=time[i];
        }
        printf("%d\n",max);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值