本质上是图的最短路径的问题:
图的最短路径
题型就是给定一个无向图,有点权,边权,你在其中某一点,到另一点的最小边权和,以及这条路上的最大点权和
算法是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;
}