题意:给出N个城市,M条无向边。每个城市都有一定数目的救援小组,所有边的边权已知。现在给出起点和终点,求从起点到终点的最短路径条数及最短路径上的救援小组数目之和。如果有多条最短路径,则输出数目之和最大的。
分析:
1.第一标尺:顶点i到源点s的最短路径长度 第二标尺:最短路径上的最大点权之和和最短路径条数。
2.图的存储用邻接表实现,整个图为vector
有两个地方需要注意:(1)输入边的时候,边两端顶点要分别push_back(node),即把对方加入。
(2)遍历某个顶点的邻接顶点时,j只是表示其第j个l邻接点,邻接点的编号要用id表示,不可混淆。
3.对于新加入的顶点u
(1)若可以更新到达顶点id的最短路径,即d[u] + Adj[u][j].cost < d[id]
则更新d[id]、sum[id]和num[id]。
(2)若最短路径长度不变,但是可以更新救援队的数目,即 d[u] + Adj[u][j].cost == d[id]&&num[u]+cnt[id]>num[id]
则更新sum[id]和num[id]。
(3)若最短路径长度和最多救援队数目均不可更新,即d[u] + Adj[u][j].cost == d[id] && num[u] + cnt[id] == num[id]
则更新sum[id]。
注意:若最短路径可以更新,意味着找到一条更短的路径,要将sum[id]覆盖,若最短路径未更新,则只要在原来的基础上累加sum[id]。
4.循环要进行N次,且开始时不能将s标记为true,即不能将s加入S,否则开始时找不到第一个满足条件的u。
#include
#include
#include
#include
#pragma warning(disable:4996)
using namespace std;
const int maxn = 510;
const int INF = 10000000;
struct Node {
int v;
int cost;
};
int d[maxn];
int num[maxn]; //从源点到顶点i的最多救援队数目
bool mark[maxn];
int cnt[maxn]; //存储的是每个结点救援队的数量
int sum[maxn]; //从源点到顶点i的最短路径条数
vector Adj[maxn];
void Dijkstra(int s, int N) {
fill(d, d + maxn, INF);
memset(num, 0, sizeof(num));
memset(sum, 0, sizeof(sum));
memset(mark, 0, sizeof(mark));
d[s] = 0;
num[s] = cnt[s];
sum[s] = 1;
//mark[s] = true; 注意开始的时候s不能加入集合S,否则找不到d[i]最小的点
//int u = s;
for (int i = 0; i < N; i++) //循环N次,且第一个找到的点一定是s
{
int u=-1, min = INF;
for (int v = 0; v < N; v++)
{
if (!mark[v] && d[v] < min)
{
u = v;
min = d[v];
}
}
if (u == -1) return; //找不到小于INF的点,说明剩余顶点和起点s不连通
mark[u] = true;
//cout << u << endl; //依次打印出加入顶点集合的顶点
for (int j = 0; j < Adj[u].size(); j++)
{
int id = Adj[u][j].v;
if (!mark[id] && d[u] + Adj[u][j].cost < d[id])
{
d[id] = d[u] + Adj[u][j].cost;
num[id] = num[u] + cnt[id];
sum[id] = sum[u]; //即优化了id
}
else if (!mark[id] && d[u] + Adj[u][j].cost == d[id]&&num[u]+cnt[id]>num[id])
{
num[id] = num[u] + cnt[id];
sum[id]+= sum[u]; //即优化了id
}
else if (!mark[id] && d[u] + Adj[u][j].cost == d[id] && num[u] + cnt[id] == num[id])
{
sum[id] += sum[u]; //累加可能的路径
}
}
}
}
int main()
{
int N, M,C1,C2;
while (scanf("%d%d%d%d", &N, &M, &C1, &C2) != EOF)
{
for (int i = 0; i < N; i++)
scanf("%d", &cnt[i]);
for (int i = 0; i < N; i++)
Adj[i].clear();
int c1, c2, L;
for (int i = 0; i < M; i++)
{
scanf("%d%d%d", &c1, &c2, &L);
Node n1,n2;
n1.cost = L;
n1.v = c2;
Adj[c1].push_back(n1);
n2.cost = L;
n2.v = c1;
Adj[c2].push_back(n2);
}
//for (int i = 0; i < N; i++)
//cout << Adj[i].size() << endl;;
Dijkstra(C1, N);
printf("%d %d\n", sum[C2], num[C2]);
}
system("pause");
return 0;
}
/*
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
Output:
2 4
*/