PATA 1003 Emergency

在这里插入图片描述
在这里插入图片描述

题记

本题在最基础的单源结点最短距离的基础上增加了点权,并且让求出最短距离路线的条数。
关键思路(如何求最短路线条数和召集最多的救援人员)
假设当前到原点s最短距离的点是u,u再往外走一步的结点记为v,u的最短距离是d[u],它的最短路线数目是num[u],它所在位置(距离最短的前提下)最多能到达的救援人员数目是w[u],v点同样,G[u][v]记录了u到v的距离此时u的相关信息是已经是最优的了
1.如果d[u]+G[u][v]<d[v],说明v借助u可以达到更优,那么d[v]=d[u]+G[u][v];
v的最短路线数目被覆盖为num[u],即num[v]=num[u],因为原来保存的不是当前最优的,原来的那些路线我们都不需要了;此时能到达救援人员数目为w[v]=w[u]+weight[v],因为距离最短是主要的,而救援人员的数目是第二条件,在距离更短的情况下,即便救援人员数目不是最多的也要用这条路线;
2.如果d[u]+G[u][v]=d[v],那么此时最短距离用不着更新;
v的最短路线数目就等于在原来已有的最短路线数目基础上再增添num[u]数目的最短路线,这些最短路线都可以用;(注意不是加1)
救援人员数目此时需要判断一下,原有线路当中救援人员数目多还是经过u的路线所能召集到的救援人员数目多,取最大值;
另外需要注意的是一定要注意,不管是找当前距离起点s最短的u还是从u出发更新相邻顶点,都一定要先判断结点是否访问过.

代码如下

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int Maxv=500+10;
const int INF=1000000000;

//输入
//城市数量、边数、起点、终点
int n,m,st,ed;
//图、各城市点权
int G[Maxv][Maxv],weight[Maxv];
//最大点权,最短距离,最短距离路线数
int w[Maxv],d[Maxv],num[Maxv];
bool visit[Maxv]={false};

void dijstra(int s){//起点为s
    memset(num,0,sizeof(num));
    memset(w,0,sizeof(w));
    fill(d,d+Maxv,INF);
    d[s]=0;
    num[s]=1;
    w[s]=weight[s];
    for(int i=0;i<n;i++){//一共n个顶点,循环n次
        int u=-1,MIN=INF;
        for(int j=0;j<n;j++){
            if(visit[j]==false&&d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }
        if(u==-1) //剩下的结点和起点s不连通
            return;
        visit[u]=true;
        for(int v=0;v<n;v++){
            if(visit[v]==false&&G[u][v]!=INF){
                if(d[u]+G[u][v]<d[v]){//借助u可以使v的最短距离更优
                    d[v]=d[u]+G[u][v];
                    w[v]=w[u]+weight[v];
                    num[v]=num[u];
                }
                else if(d[u]+G[u][v]==d[v]){
                    if(w[u]+weight[v]>w[v]){
                        w[v]=w[u]+weight[v];
                    }
                    num[v]+=num[u];
                }
            }

        }
    }

}


int main()
{
    scanf("%d %d %d %d",&n,&m,&st,&ed);
    for(int i=0;i<n;i++)
        scanf("%d",&weight[i]);
    fill(G[0],G[0]+Maxv*Maxv,INF);
    int u,v;
    for(int i=0;i<m;i++){
        scanf("%d %d",&u,&v);
        scanf("%d",&G[u][v]);
        G[v][u]=G[u][v];
    }
    dijstra(st);
    printf("%d %d\n",num[ed],w[ed]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值