PTA-KK的传言

一、题目

股票经纪人KK想要在一群人(n个人的编号为0~n-1)中散布一个传言,传言只通过认识的人进行传递,在两个认识的人之间传递消息所需要的时间各有不同,在一群人中,KK想要找出以哪个人为起点开始传递这个传言,可以在耗时最短的情况下认所有人都收到消息。
请编写程序帮KK解决这个问题。

输入格式:
先输入n m,其中n是人数,m是可传递消息的人群关系数量,以下m行分别输入a b t ,表示 a 向 b 可传递消息,消耗的时间为t。
当输入0时,表示输入结束。

输出格式:
输出从第几个人开始传递传言耗时最短。如果无解,就输出-1。
PTA-KK的传言_第1张图片

二、代码

/*
    描述:kk的传言,上传到csdn版本
    日期:221101
    思路:
    (1)使用floyd算法获取每个点到其他点的最小路径
    (2)然后算出每个点到其他点最小路径之和,取最小的之和,也即所求的最佳起始点
    (3)可能有多个最佳起始点,采取最后一个为输出
    注意:
    (1)#define MAX_INT 2147483647,#define MIN_INT -2147483684,初始值设置的是最大的整型,
    所以一旦有相加的运算,结果就会溢出变成负数,造成出错,所以要么把MAX_INT定义的小一些,或者用
    if语句将这种情况避免掉,见floyd()函数中
    (2)最小路径过程中,当涉及到i==j的是时候,也即自己到自己的相关运算,都要跳过不管
测试数据:
(1)
4 4
0 1 2
0 2 5
0 3 1
2 3 3
0
结果:3
(2)
6 5
0 1 2
0 2 5
0 3 1
2 3 3
4 5 2
0
结果:-1
*/
#include
#include
#include
#include 
using namespace std;

#define MAX_INT 2147483647
#define MIN_INT -2147483684


vector<vector<int>>dp = { 101, vector<int>(101, MAX_INT) };//作为储存最小路径的矩阵

//使用floyd算法获取每个点到其他点的最小路径
void floyd(int n)
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            for (int k = 0; k < n; k++)
            {
                if(j==k) continue;
                //这里有个小坑,因为设置的MAX_INT是最大的整型,所以dp[j][i]和dp[i][k]要是有一个是
                //MAX_INT的话,那么加和之后的结果就是负数,所以再做min就会出错
                //所以这里就用一个if语句避免
                if(dp[j][i]==MAX_INT||dp[i][k]==MAX_INT) continue;
                dp[j][k] = min(dp[j][k], dp[j][i] + dp[i][k]);
            }
}

//算出每个点到其他点最小路径之和,取最小的之和,也即所求的最佳起始点
int get_res(int n)
{
    //计算每一个中心点的花费和
    vector<int>res_sum;
    for (int i = 0; i < n; i++)
    {
        int sum_n = 0;
        for (int j = 0; j < n; j++)
        {
            if (i == j) continue;
            sum_n += dp[i][j];
            if (dp[i][j] == MAX_INT) 
            //若是dp[i][j]的值还等于初始值MAX_INT,那么说明i和j之间并不相通
            //则是题目中说的无解的,返回-1
                return -1;
        }
        res_sum.push_back(sum_n);
    }


    //找出最小的花费和和其下标
    int min_sum = res_sum[0];
    int min_pos = 0;
    for (int i = 1; i < n; i++)
    {
        if (min_sum >= res_sum[i])
        //可能有多个最佳起始点,采取最后一个为输出,所以这里用的是>=而非>
        {
            min_sum = res_sum[i];
            min_pos = i;
        }
    }
    return min_pos;
}

int main()
{
    int n, m;
    while (1)
    {
        //输入点、边个数
        cin >> n;
        if (n == 0) return 0;
        cin >> m;
        //输入边的权重数据
        while (m--)
        {
            int a, b, v;
            cin >> a >> b >> v;
            dp[a][b] = v;
            dp[b][a] = v;
        }

        //处理数据获取结果
        floyd(n);
        int res = get_res(n);

        //输出结果
        cout << res << endl;
        //每次输出完成后要重新将dp数组初始化
        vector<vector<int>>dp = { 101,vector<int>(101,MAX_INT) };
    }
    return 0;
}

你可能感兴趣的:(SCNU_PTA,算法,c++,图论)