5-35 城市间紧急救援 (25分)

原创 2016年08月30日 11:26:44

5-35 城市间紧急救援 (25分)

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

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

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

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

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算法就是生而为了解决这种题目的。不过这道题需要我们找出所有最短路的数量,那就必须在原来的标准代码上做点修改,不能找到终点就跳出Dijkstra函数,而是要完全遍历全图。
后面递归输出路径的时候则是利用了先前Dijkstra函数中生成使用的两组数据:从起点S到各结点的最短路径长度,从起点S到各结点的救援队数量;利用这个数据,我们从终点开始遍历他的所有边,若存在某条边DA连接终点D和某结点A使得“从起点S到A能获得的最大救援队数量+D点的救援队数量==从起点S到D能获得的最大救援队数量”&&“从起点S到A的最短路径长度+边DA的长度==从起点S到D的最短路径长度”那么这个结点A就必然是起点S到终点D最短路径最多救援队路径上最靠近终点D的那个驿站。

点击访问 PTA-测验

#include <stdio.h>
#include<stdlib.h>
#define FULL 250001
/*
提交时间    状态  分数  题目  编译器 耗时  用户
2018/1/23 11:57:04  答案正确    25  7-35    C (gcc) 238 ms  569985011
测试点 提示  结果  耗时  内存
0   sample  答案正确    2 ms    240KB
1   5条不同的最短路    答案正确    2 ms    244KB
2   最小N和M   答案正确    2 ms    156KB
3   最大N和M,随机数据构成完全图 答案正确    238 ms  2196KB
*/
typedef struct node *Node;
typedef struct {
    int Node;//目标结点
    int Lenth;//边长
} data;
struct node {
    data Reached[501];//与之有边连接的结点集合
    int right;//集合里的结点个数
};

int teams[501];//保存每个结点带有的救援队数目
int Lenth[501][3];//[0]记录从起点出发到各结点的路径长度 ;[1]记录该路径能获取的救援队总数;【2】记录等长路径条数
Node Map;//地图

int cmp(const void*a,const void*b) {//
    data*x=(data*)a;
    data*y=(data*)b;
    if(x->Lenth!=y->Lenth) {
        return x->Lenth-y->Lenth;
    } else if(teams[x->Node]!=teams[y->Node]) {
        return teams[y->Node]-teams[x->Node];
    } else  return teams[x->Node]-teams[y->Node];
}

void Dijkstra(int);
void DFS(int,const int);
int main() {
    int N,M,S,D;//结点数、边数、起点、终点
    scanf("%d%d%d%d",&N,&M,&S,&D);

    Map=(Node)malloc(sizeof(struct node)*N);//初始化地图上的结点
    for(int i=0; i<N; Map[i++].right=0);

    for(int i=0; i<N; scanf("%d",&teams[i++]));//读入每个结点的价值——城市拥有的救援队数量

    {
        //读入地图信息,并排序整理
        while(M--) {
            int a,b,lenth;
            scanf("%d%d%d",&a,&b,&lenth);
            Map[a].Reached[Map[a].right].Node=b;
            Map[a].Reached[Map[a].right++].Lenth=lenth;
            Map[b].Reached[Map[b].right].Node=a;
            Map[b].Reached[Map[b].right++].Lenth =lenth;
        }
        for(int i=0; i<N; i++) {
//          printf("\n%d:",i);
            qsort(Map[i].Reached,Map[i].right,sizeof(data),cmp);
            for(int j=0; j<Map[i].right; j++) {
//              printf("{%d-%d}",Map[i].Reached[j].Node,Map[i].Reached[j].Lenth);
            }
        }
    }

    for(int i=0; i<N; Lenth[i++][0]=FULL); //[0]初始化设定从起点到所有其他结点的路径长度为无穷;
    Lenth[S][0]=0;
    Lenth[S][1]=teams[S];
    Dijkstra(S);
    printf("%d %d\n",Lenth[D][2],Lenth[D][1]);
    DFS(D,S);
    printf("%d",D);
    return 0;
}


void Dijkstra(int a) {//戴克斯特拉算法

    for(int i=0; i<Map[a].right; i++) {
        data temp=Map[a].Reached[i];
        if(Lenth[a][0]+temp.Lenth<Lenth[temp.Node][0]) {
            Lenth[temp.Node][0]=Lenth[a][0]+temp.Lenth;
            Lenth[temp.Node][1]=Lenth[a][1]+teams[temp.Node];
            Lenth[temp.Node][2]=1;
            Dijkstra(temp.Node);
        } else if(Lenth[a][0]+temp.Lenth==Lenth[temp.Node][0]) {
            if(Lenth[a][1]+teams[temp.Node]>Lenth[temp.Node][1]) {
                Lenth[temp.Node][1]=Lenth[a][1]+teams[temp.Node];
            }
            ++Lenth[temp.Node][2];
            Dijkstra(temp.Node);
        }
    }

}

void DFS(int dd,const int S) {//深度优先,从终点递归回溯, 如果存在某个结点:它到终点的边长加上它到起点的长度== 终点到原点的长度&&它到起点的救援队数量+终点的救援队数量== 起点到终点的救援队数量,那么这个结点一定是最短路上的一个结点。
    if(dd==S)return;
    for(int i=0; i<Map[dd].right; i++) {
        data temp=Map[dd].Reached[i];
        if(Lenth[temp.Node][0]+temp.Lenth==Lenth[dd][0]&&
                Lenth[temp.Node][1]+teams[dd]==Lenth[dd][1]) {
//          printf("*");
            DFS(temp.Node,S);
            printf("%d ",temp.Node);
        }
    }
}
版权声明:写这些东西还是问了交流进步,如果你有不同的方法、见解,欢迎交流分享。文章中附的代码只传达当时我的一种做法,并非我认为最好的。

城市间紧急救援

5-28 城市间紧急救援   (25分) 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接...
  • Roosevelty
  • Roosevelty
  • 2016年01月29日 19:00
  • 1903

PTA-数据结构 5-35 城市间紧急救援 (25分)

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求...
  • flx413
  • flx413
  • 2016年11月29日 20:03
  • 666

进阶项目7-紧急救援

#include #include #include typedef struct { float x; float y; int people; }rescuepoi...
  • zyjiscainiao
  • zyjiscainiao
  • 2016年07月29日 22:17
  • 443

PAT 5-35 城市间紧急救援

5-35 城市间紧急救援   (25分) 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连...
  • qq_32541007
  • qq_32541007
  • 2016年07月28日 17:04
  • 575

PAT L2-1. 紧急救援 (Dijkstra扩展)

题目链接:https://www.patest.cn/contests/gplt/L2-1 L2-1. 紧急救援 时间限制 200 ms 内存限制 65536 kB 代码...
  • Strokess
  • Strokess
  • 2016年05月07日 20:54
  • 2171

PAT L2-001. 紧急救援 (最短路变形 Dijkstra + 记录路径)

PAT L2-001. 紧急救援 (最短路变形 Dijkstra + 记录路径)
  • Tc_To_Top
  • Tc_To_Top
  • 2016年05月16日 18:51
  • 3310

pat 城市救援 最短路

5-12 城市间紧急救援   (25分) 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城...
  • johsnows
  • johsnows
  • 2016年07月01日 17:16
  • 420

5-35 城市间紧急救援 (25分)

5-35 城市间紧急救援   (25分) 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连...
  • qq_34125999
  • qq_34125999
  • 2016年05月06日 19:58
  • 1966

6-08. 城市间紧急救援(25)--Dijkstra

6-08. 城市间紧急救援(25)题目地址 时间限制 150 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作为一个城市的应急救援队伍的负...
  • qq_26437925
  • qq_26437925
  • 2015年08月13日 15:44
  • 1434

L2-1. 紧急救援 题目详解

L2-1. 紧急救援时间限制200 ms 内存限制65536 kB 代码长度限制8000 B 判题程序Standard作者陈越 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地...
  • var1994
  • var1994
  • 2016年04月22日 01:08
  • 1384
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:5-35 城市间紧急救援 (25分)
举报原因:
原因补充:

(最多只允许输入30个字)