紧急救援,Dijkstra

Dijkstra算法 最短路问题,边权为正,单源最短路。

/* d[i] 从点0到点i路长→最短路
   v[i] 点i标记,是否计算完到点i最短路
   w[x][y] 点x与点y边长,未联结为INF,同一点为0 */

// 初始,清除除起始点外所有标记,令d[i]为点0与点i边长
memset(v, 0, sizeof(v));
v[0] = 1;
for (int i = 0; i < n; i++)
	d[i] = w[0][i];
// 循环n-1次,考虑每个点情况,标记n-1次
for (int i = 0; i < n; i++) {
	int x, m = INF;
	/* 所有未标记点中,寻找点0出发路长最短的点y
	   若点0到点y经过未标记点y',则到y'路长更短,所以点0到点y经过每点均已标记
	   若点0到点y有更短路长,则经过点中有某点未标记
	   若先到未标记点y'再到点y,由于到点y路长为最短之一且边权为正,绕路
	   本次循环中,点0到点y路长为最短路,标记该点y */
	for (int y = 0; y < n; y++)
		if (!v[y] && d[y] < m) 
			m = d[x=y];
	v[x] = 1;
	//更新路长,归纳可知除终点外经过点均为已标记点
	for (int y = 0; y < n; y++)
		if (d[y] > d[x] + w[x][y])
			d[y] = d[x] + w[x][y];
}

PTA L2-001 紧急救援
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式: 输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:
2 60
0 1 3

最短路径条数不是最短路有多少边长
Dijkstra基础上增加,救援队数量,路径条数,父亲指针回溯路径
更新路长(最短路)时同步更新
若 到新标记结点x再从x直接到y 路长比 经原标记点 更短,way[y]=way[x]
若相等,两种走法都是最短路,way[y]+=way[x]
此时考虑集结队伍数量,更新回溯路径和集结队伍数量

#include 
#include 
#include 
#include 
#define INF 300000
int city[510], mark[510], dis[510], last[510], way[510], sum[510], len[510][510];
/* 城市救援队数,城市标记与否,出发地到该城市最短距离,到该城市最短时上一步所在城市,出发地到城市最短路径数量,到城市集结队伍,两城市之间路长 */
int n, m, s, d;
void f(int y) {
    if (y>=0) {
        f(last[y]);
        if (y==s) printf("%d", y);
        else printf(" %d", y);
    }
}
int main(){
    int i, j, k;
    scanf("%d%d%d%d", &n, &m, &s, &d);
    memset(mark, 0, sizeof(mark));
    memset(way, 0, sizeof(way));
    memset(sum, 0, sizeof(sum));
    for (i=0; i<n; i++) {
        for (j=0; j<n; j++) len[i][j]= (i==j? 0:INF);
        scanf("%d", &city[i]);
        last[i]=-1;
        dis[i]=INF;
    }
    for (i=0; i<m; i++) {
        scanf("%d%d", &j, &k);
        scanf("%d", &len[j][k]);
        len[k][j]=len[j][k];
    }
    for (i=0; i<n; i++)
        if (len[i][s]<INF) {
            dis[i]=len[i][s];
            sum[i]=city[s]+city[i];
            last[i]=s;
            way[i]=1;
        }
    sum[s]=city[s];
    mark[s]=1;
    last[s]=-1;
    while(1) {
        int x, y, min=INF;
        for (y=0; y<n; y++)
            if (!mark[y] && dis[y]<min) {
                min=dis[y];
                x=y;
            }
        if (x==d||min==INF) break;
        mark[x]=1;
        for (y=0; y<n; y++)
            if (!mark[y]) {
                if (dis[y]==dis[x]+len[x][y]) {
                    way[y]+=way[x];
                    if (sum[y]<sum[x]+city[y]) {
                        sum[y]=sum[x]+city[y];
                        last[y]=x;
                    }
                }
                else if (dis[y]>dis[x]+len[x][y]) {
                    dis[y]=dis[x]+len[x][y];
                    sum[y]=sum[x]+city[y];
                    way[y]=way[x];
                    last[y]=x;
                }
            }
    }
    printf("%d %d\n", way[d], sum[d]);
    f(d);
    printf("\n");
    return 0;
}

《算法入门》11.2.1 Dijkstra算法

你可能感兴趣的:(pta,L2,3)