zoukankan      html  css  js  c++  java
  • PAT Advanced 1003 Emergency (25) [Dijkstra DFS]

    题目

    As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.
    Input Specification
    Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (<=500) – the number of cities (and the cities are numbered from 0 to N-1), M – the number of roads, C1 and C2 – the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.
    Output Specification
    For each test case, print in one line two numbers: the number of diferent shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.
    Sample 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
    Sample Output
    2 4

    题意

    国家紧急救援组织的小组分布在全国各个城市,地图标出了每个城市的救援小组数目和城市间的公路(稀疏城市),若出现紧急情况,需要从当前城市出发走最短路径(标准:耗时最短)到达需要救援的城市,同时,要求路上能尽量找到更多帮手协助救援
    输入:顶点和边,领导组所在城市,各个城市急救小组的数目
    输出:最短路径数目和能找到最多救援小组助手的数目

    题目分析

    已知网图点权-城市急救小组数目,边权-城市间路程耗时,求最短路径,要求该最短路径点权和最大
    输入:顶点,点权,边,边权
    输出:最短路径数目 所有最短路径中最大点权和

    解题思路

    1. 存储图

    存储边和边权

    1.1 邻接表(题目已知稀疏图,用邻接表比较合适)
    1.2 邻接矩阵

    存储点权

    整型数组

    2. 求最短路径

    • Dijkstra算法求最短路径,每次收集一个顶点到最短路径中时,若使得起点到其他顶点的最短路径更短,则更新dist[i],若等于dist[i],需比较其点权和,若点权和更大则更新dist[i];

    注:本题不需要记录路径,int path[n]可以省略

    Code

    Code 01(邻接表(Dijkstra))

    #include <iostream>
    #include <vector>
    using namespace std;
    const int maxn=510;
    const int INF=9999999;
    int n,c1,c2,vw[maxn]; //g边;vw点权
    int dist[maxn],col[maxn];// col已经找到最小路径的顶点收集到col中
    int w[maxn],num[maxn];
    struct node{
    	int v;
    	int w;
    };
    vector<node> gw[maxn]; //gw边权;
    /* dijkstra算法 求最短路径 */
    int dmin() {
    	int min=INF,mini=0;
    	for(int i=0; i<n; i++) {
    		if(col[i]==1)continue; // 跳过被收集的点
    		if(min>dist[i]) {
    			min=dist[i]; //没有被收集的顶点中的最小者
    			mini=i;
    		}
    	}
    	return mini;
    }
    void dijkstra(int c) {
    	fill(dist,dist+n,INF);
    	dist[c]=0;
    	num[c]=1; //起点c1到其直连的顶点,都只有一条最短路径
    	w[c]=vw[c]; //起点c1的点权
    	for(int i=0; i<n; i++) {
    		int min=dmin(); //当前dist中最小值对应的顶点
    		if(min==c2) break; //已找到目标顶点
    		col[min]=1;
    		for(int j=0; j<gw[min].size(); j++) {
    			node e = gw[min][j]; 
    			if(col[e.v]==1)continue; //跳过 已被收集的顶点
    			if(dist[min]+e.w<dist[e.v]) {
    				dist[e.v]=dist[min]+e.w; //更新dist
    				w[e.v]=w[min]+vw[e.v]; // 更新c1到j的最短所有路径中的最大权重和
    				num[e.v]=num[min]; // 更新c1到j的最短路径数
    			} else if(dist[min]+e.w==dist[e.v]) {
    				if(w[min]+vw[e.v]>w[e.v])
    					w[e.v]=w[min]+vw[e.v];
    				num[e.v]+=num[min];
    			}
    		}
    	}
    }
    int main(int argc,char * argv[]) {
    	int m,a,b,r;
    	scanf("%d %d %d %d",&n,&m,&c1,&c2);
    	for(int i=0; i<n; i++)
    		scanf("%d",&vw[i]); //点权
    	for(int i=0; i<m; i++) {
    		scanf("%d %d %d",&a,&b,&r);
    		gw[a].push_back({b,r});
    		gw[b].push_back({a,r});
    	}
    	dijkstra(c1);
    	printf("%d %d",num[c2],w[c2]);
    	return 0;
    }
    

    Code 02(Dijkstra)

    #include <iostream>
    using namespace std;
    const int maxn=510;
    const int INF=9999999;
    int n,c1,c2,gw[maxn][maxn],vw[maxn]; //g边;gw边权;vw点权
    int dist[maxn],col[maxn];// col已经找到最小路径的顶点收集到col中
    int w[maxn],num[maxn];
    /* dijkstra算法 求最短路径 */
    int dmin() {
    	int min=INF,mini=0;
    	for(int i=0; i<n; i++) {
    		if(col[i]==1)continue; // 跳过被收集的点
    		if(min>dist[i]) {
    			min=dist[i]; //没有被收集的顶点中的最小者
    			mini=i;
    		}
    	}
    	return mini;
    }
    void dijkstra(int c) {
    	fill(dist,dist+n,INF);
    	dist[c]=0;
    	num[c]=1; //起点c1到其直连的顶点,都只有一条最短路径
    	w[c]=vw[c]; //起点c1的点权
    	for(int i=0; i<n; i++) {
    		int min=dmin(); //当前dist中最小值对应的顶点
    		if(min==c2) break; //已找到目标顶点
    		col[min]=1;
    		for(int j=0; j<n; j++) {
    			if(gw[min][j]==0||col[j]==1)continue; //跳过 已被收集的顶点
    			if(dist[min]+gw[min][j]<dist[j]) {
    				dist[j]=dist[min]+gw[min][j]; //更新dist
    				w[j]=w[min]+vw[j]; // 更新c1到j的最短所有路径中的最大权重和
    				num[j]=num[min]; // 更新c1到j的最短路径数
    			} else if(dist[min]+gw[min][j]==dist[j]) {
    				if(w[min]+vw[j]>w[j])
    					w[j]=w[min]+vw[j];
    				num[j]+=num[min];
    			}
    		}
    	}
    }
    int main(int argc,char * argv[]) {
    	int m,a,b,r;
    	scanf("%d %d %d %d",&n,&m,&c1,&c2);
    	for(int i=0; i<n; i++)
    		scanf("%d",&vw[i]); //点权
    	for(int i=0; i<m; i++) {
    		scanf("%d %d %d",&a,&b,&r);
    		gw[a][b]=gw[b][a]=r; //边权
    	}
    	dijkstra(c1);
    	printf("%d %d",num[c2],w[c2]);
    	return 0;
    }
    

    Code 03 (Dijkstra+DFS)

    #include <iostream>
    #include <vector>
    #include <cstring>
    using namespace std;
    const int maxn = 510;
    const int Inf = 0xfffffff;
    int vg[maxn],wg[maxn][maxn];
    int dist[maxn],visit[maxn];
    int n,c1,c2,pathCnt,maxHandsNum=-1;
    vector<int> path[maxn],tempPath;
    void dfs(int v){
    	if(v==c1){
    		pathCnt++; 
    		tempPath.push_back(v);
    		int handsCnt=0;
    		for(int i=tempPath.size()-1;i>=0;i--){
    			handsCnt+=vg[tempPath[i]];
    		}
    		if(handsCnt>maxHandsNum){
    			maxHandsNum=handsCnt;
    		}
    		tempPath.pop_back();
    		return;
    	}
    	tempPath.push_back(v);
    	for(int i=0;i<path[v].size();i++){
    		dfs(path[v][i]);
    	}
    	tempPath.pop_back();
    }
    void dijkstra(int v) {
    	// 1 初始化
    	fill(dist, dist+maxn, Inf); //dist初始化为无穷大
    	memset(visit, 0, sizeof(visit)); //visit 初始化为未被访问
    	dist[v]=0;
    	for(int i=0; i<n; i++) {
    		// 2 找最小值
    		int mini=-1,min=Inf;
    		for(int j=0; j<n; j++) {
    			if(visit[j]==0&&min>dist[j]) { //在未处理的顶点中找到dist最小
    				min=dist[j];
    				mini=j;
    			}
    		}
    		if(mini==-1||mini==c2)break; //如果最小值为目标顶点,可以剪枝 
    		visit[mini]=1; //该城市已被收集到最短路径
    		for(int j=0; j<n; j++) {
    			if(visit[j]==1||wg[mini][j]==Inf)continue; //已被处理 或 没有边 
    			if(dist[mini]+wg[mini][j]<dist[j]){
    				dist[j]=dist[mini]+wg[mini][j];
    				path[j].clear();
    				path[j].push_back(mini);
    			} else if(dist[mini]+wg[mini][j]==dist[j]){
    				path[j].push_back(mini);
    			}
    		}
    	}
    }
    int main(int argc,char * argv[0]) {
    	fill(wg[0], wg[0]+maxn*maxn, Inf); //边权初始化为无穷大 
    	int m,len,s1,s2;
    	scanf("%d %d %d %d",&n,&m,&c1,&c2);
    	for(int i=0; i<n; i++) {
    		scanf("%d",&vg[i]); //点权,每个城市的医护人员数
    	}
    	for(int i=0; i<m; i++) {
    		scanf("%d%d%d",&s1,&s2,&len);
    		wg[s1][s2]=wg[s2][s1]=len; // 边权,每条路的长度
    	}
    	dijkstra(c1);
    	dfs(c2);
    	if(pathCnt==-1)pathCnt=0;
    	if(maxHandsNum==-1) maxHandsNum=0;
    	if(c1==c2){ //有可能出现起点和终点相同的情况 
    		pathCnt=1;
    		maxHandsNum=vg[c2];
    	} 
    	printf("%d %d",pathCnt,maxHandsNum);
    	return 0;
    }
    

  • 相关阅读:
    团队项目——站立会议DAY14
    团队项目——站立会议DAY13
    团队项目——站立会议DAY12
    团队项目——站立会议 DAY11
    团队项目——站立会议DAY10
    团队项目——站立会议DAY9
    团队项目——站立会议 DAY8
    团队项目——站立会议DAY7
    团队项目——站立会议DAY6
    作业五:团队项目——项目启动及需求分析
  • 原文地址:https://www.cnblogs.com/houzm/p/12367280.html
Copyright © 2011-2022 走看看