PAT A1003 Emergency(邻接表实现)

题意:给出N个城市,M条无向边。每个城市都有一定数目的救援小组,所有边的边权已知。现在给出起点和终点,求从起点到终点的最短路径条数及最短路径上的救援小组数目之和。如果有多条最短路径,则输出数目之和最大的。

分析:

1.第一标尺:顶点i到源点s的最短路径长度 第二标尺:最短路径上的最大点权之和和最短路径条数。

2.图的存储用邻接表实现,整个图为vector Adj[N],图中每个顶点对应一个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
*/

 

你可能感兴趣的:(机试准备)