PAT甲级1003 Emergency

本质上是图的最短路径的问题:

图的最短路径

题型就是给定一个无向图,有点权,边权,你在其中某一点,到另一点的最小边权和,以及这条路上的最大点权和

算法是Dijkstra算法。

首先我们定义所需要的内容:

int n, m;//点数,边数
int c1, c2;//起始位置
int nodew[505];//点权
int loadw[505][505];//邻接矩阵,边权
int loadsumw[505];//边权和
int vis[505];//是否访问过的标记
int loadnum[505];//道路数量
int nodesumw[505];//点权和

将所有的边权设为极大值

for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            loadw[i][j] = INF;

因为要求边权和的最小值,所以将边权和设为极大值,

for (int i = 0; i < n; i++)
        loadsumw[i] = INF;
Dijkstra算法:

将我们所在位置的数据初始化,边权和为0,边数为1,点权和为自身点权

    loadsumw[root] = 0;
    nodesumw[root] = nodew[root];
    loadnum[root] = 1;

由于有n个数,所以我们要进行n次循环计算

for (int i = 0; i < n; i++)

求出当下的最小边权和,然后用它来缩短其他的边权和,

        int temp = -1;
        int minn = INF;
        for (int j = 0; j < n; j++)
        {
            if (vis[j] == 0 && loadsumw[j] < minn)
            {
                minn = loadsumw[j];
                temp = j;
            }
        }

如果当下未找到小于极大值的边权和,说明已经没有与我们所在的节点连通的节点了

        if (temp == -1)
            return;

如果找到则标记,这里我们称为temp节点

 vis[temp] = 1;

对所有未标记的与temp节点连通的节点:

如果temp边权和+temp节点到该节点的边权小于原边权和,则修改该节点边权和,点权和,路的数量。

如果temp边权和 + temp节点到该节点的边权等于原边权和,增加路的数量,并且如果点权和更大则修改点权和。

        for (int j = 0; j < n; j++)
        {
            if (vis[j] == 0 && loadw[temp][j] != INF)
            {
                if (loadsumw[j] > loadsumw[temp] + loadw[temp][j])
                {
                    loadsumw[j] = loadsumw[temp] + loadw[temp][j];
                    loadnum[j] = loadnum[temp];
                    nodesumw[j] = nodesumw[temp] + nodew[j];
                }
                else if (loadsumw[j] == loadsumw[temp] + loadw[temp][j])
                {
                    if (nodesumw[j] < nodesumw[temp] + nodew[j])
                        nodesumw[j] = nodesumw[temp] + nodew[j];
                    loadnum[j] += loadnum[temp];
                }
            }
        }

以下为完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
int n, m;
int c1, c2;
int nodew[505];
int loadw[505][505];
int loadsumw[505];
int vis[505];
int loadnum[505];
int nodesumw[505];
void Dijkstra(int root)
{
    loadsumw[root] = 0;
    nodesumw[root] = nodew[root];
    loadnum[root] = 1;

    for (int i = 0; i < n; i++)
    {
        
        int temp = -1;
        int minn = INF;
        for (int j = 0; j < n; j++)
        {
            if (vis[j] == 0 && loadsumw[j] < minn)
            {
                minn = loadsumw[j];
                temp = j;
            }
        }
   
        if (temp == -1)
            return;
        vis[temp] = 1;
        for (int j = 0; j < n; j++)
        {
            if (vis[j] == 0 && loadw[temp][j] != INF)
            {
                if (loadsumw[j] > loadsumw[temp] + loadw[temp][j])
                {
                    loadsumw[j] = loadsumw[temp] + loadw[temp][j];
                    loadnum[j] = loadnum[temp];
                    nodesumw[j] = nodesumw[temp] + nodew[j];
                }
                else if (loadsumw[j] == loadsumw[temp] + loadw[temp][j])
                {
                    if (nodesumw[j] < nodesumw[temp] + nodew[j])
                        nodesumw[j] = nodesumw[temp] + nodew[j];
                    loadnum[j] += loadnum[temp];
                }
            }
        }
    }
}
int main()
{
    scanf("%d %d %d %d", &n, &m, &c1, &c2);
    for (int i = 0; i < n; i++)
        scanf("%d", &nodew[i]);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
                loadw[i][j] = INF;
    for (int i = 0; i < m; i++)
    {
        int temp1, temp2, temp3;
        scanf("%d %d %d", &temp1, &temp2, &temp3);
        loadw[temp1][temp2] = temp3;
        loadw[temp2][temp1] = temp3;
    }
     for (int i = 0; i < n; i++)
        loadsumw[i] = INF;
    Dijkstra(c1);
    printf("%d %d\n", loadnum[c2], nodesumw[c2]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值