甲级 1003 Emergency

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1​ and C2​ - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1​, c2​ and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1​ to C2​.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1​ and C2​, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

本题的大意就是:首先给你每个城市的救援队的个数,其次给你每个城市和其相邻的城市的路径的一个邻接矩阵,让你求得出发地到目的地的最短距离的条数和可以凑集的最多的救援队的个数

 本题的思路就是:使用迪杰斯特拉算法去求解,需要使用一个二维数组去表示邻接矩阵去存各个节点的连接情况并且存储各个节点的路径长度,还需要三个一维数组存储从初始节点开始到各个节点的最短距离,最多人数和最短距离的条数

废话不多说,直接上代码

#include<iostream>
using namespace std;
#define MAX 10000
void dijkstra();

int n,m,c1,c2;
int helper[MAX];//记录救援人员的个数
int gra[MAX][MAX];//记录权图
bool visit[MAX];//记录某一个节点是否被用过
int dis[MAX];//记录从起始节点到其他目的节点的最短路径的距离
int helpermax[MAX];//记录从起始节点到其他目的节点的最大救援人数
int count[MAX];//记录从起始节点到其他节点的最短路径的条数


int main()
{
    cin>>n>>m>>c1>>c2;
    for(int i=0;i<n;i++)
        cin>>helper[i];
    //权图一定是一个n*n的方阵
    //可以使用0x3f3f3f3f表示无穷大
    //初始化
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i!=j) gra[i][j]=0x3f3f3f3f;
            else gra[i][j]=0;
        }
    }
    
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        //路,联通后双向可走
        gra[a][b]=c;
        gra[b][a]=c;
    }
    dijkstra();
    cout<<count[c2]<<" "<<helpermax[c2];
}

void dijkstra()
{
    helpermax[c1] = helper[c1];
    dis[c1] = 0;//自己到自己距离为0
    count[c1] = 1;//自己到自己的路径方法有1种

    for(int i=0;i<n;i++)
        dis[i] = gra[c1][i];//初始化距离,和初始节点不相连的为正无穷
    
    
    for(int i=1;i<n;i++)//0号节点不需要遍历
    {
        int mindis = 0x3f3f3f3f;
        int mid = -1;//如果遍历完之后mid还为-1即可结束循环
        for(int j=0;j<n;j++)
        {
            //visit[j]==false 表示该节点没有被访问过
            if(visit[j] == false && mindis > dis[j])
            {
                mindis = dis[j];
                mid = j;
            }
        }
        if(mid == -1) break;
        visit[mid] = true;//表示已经经历过的节点
        for(int j=0;j<n;j++)
        {
            // 如果当前遍历的节点j未曾作为过中间节点
            // 并且从起始节点到j的距离dis[j]大于从起始节点到mid与从mid到j的距离之和
            if(visit[j] == false && dis[j] > dis[mid] + gra[mid][j])
            {
                //j节点的最短距离就是起始节点到mid与从mid到j的距离之和
                dis[j] = dis[mid] + gra[mid][j];
                //已经判断出了起始节点到mid与从mid到j的距离之和是最小路径
                helpermax[j] = helpermax[mid] + helper[j];
                //更新路径数
                count[j] = count[mid];
            }
            //存在一条路使得起始节点到j的距离dis[j]等于从起始节点到mid与从mid到j的距离之和
            //即就是找到了一条新的路径
            else if(visit[j] == false && dis[j] == dis[mid] + gra[mid][j])
            {
                count[j] += count[mid];
                //表明这个节点上的救援人员并不是最多的
                if(helpermax[j] < helpermax[mid] + helper[j])
                {
                    helpermax[j] = helpermax[mid] + helper[j];
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值