AlphaCat的PAT甲级1003AC纪念(Dijkstra算法)

 

首先附上原题的链接和题目:

https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376

1003 Emergency (25 分)

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, C​1​​ and C​2​​ - 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 c​1​​, c​2​​ 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 C​1​​ to C​2​​.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C​1​​ and C​2​​, 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

首先说一下题目的意思:

题目的意思就是在一张图里面,给定了起点和终点,让你求这两点之间最短路径的条数,并且统计这些条数中,可以派遣的最大部队数(每一个节点都会有一个部队数量)。

对于最短路径来说,我们使用dijkstra算法:

 

官方求最短路径步骤

算法步骤如下:

G={V,E}

1. 初始时令 S={V0},T=V-S={其余顶点},T中顶点对应的距离值

若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值

若不存在<V0,Vi>,d(V0,Vi)为∞

2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中

3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值

重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止

 

代码如下:

 

#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<climits>
using namespace std;

#define INF INT_MAX //定义int的最大值 

int main()
{
	vector<bool> visited(500,false);//用来标记节点是否访问过 
	vector<vector<int>> map(500,vector<int>(500,INF));//用来开一个二维数组 
	vector<int> troop(500,0);//当前节点的部队数量 
	vector<int> tmax(500,0);//当前节点最多可以聚集的部队 
	vector<int> dis(500,INF);//最短路径的数值 
	vector<int> ways(500,0);//最短路径的数量 
	
	int m,n,c1,c2;//若干输入 
	cin>>m>>n>>c1>>c2;
	for(int i=0;i<m;i++)
	cin>>troop[i];
	int a,b,c;
	for(int i=0;i<n;i++)
	{
		cin>>a>>b>>c; 
		map[a][b]=c;
		map[b][a]=c;
	 } 
	 
	 
	 dis[c1]=0;//第一个节点到自身最短距离是1 
	 ways[c1]=1;//初始化条数为1 
	 tmax[c1]=troop[c1];//最大可聚集部队数是当前节点部队数 
	 
	 
	 for(int j=0;j<m;j++)
	 {
	 
	 	int start=-1,min=INF;
		for(int i=0;i<m;i++)//遍历全部节点 
		 {
		 	if(!visited[i]&&dis[i]<min)//如果之前未被访问且产生于源点最短路 
		 	{//第一次找到的是0因为只有0是被初始化了 
		 		min=dis[i];//标记当前最短,更新min 
		 		start=i;//标记该接下去找的点 
			 }
		 }
		 
		 if(start==-1)break;//全部已被访问,说明图已被搜索完毕 
		 visited[start]=true;//标记接下去要找的点为已访问(以下统称start) 
		 
		 for(int i=0;i<m;i++)//寻找从start点出发可到达的i边 
		 {
		 	if(!visited[i]&&map[start][i]!=INF)//未被访问且start和i直接存在路径联通 
		 	{
		 		
		 		if(dis[start]+map[start][i]<dis[i])//如果从start点走总路程小于之前的路程 
		 		{						//说明这条路是当前最短路径,需要更新 
		 			dis[i]=dis[start]+map[start][i];//更新 
		 		ways[i]=ways[start];//如果是最短路,更新最短路条数为新的最短路条数 
		 		tmax[i]=troop[i]+tmax[start];//因为是最短路,所以之前的要被刷新,无需判断 
				 }
				 else if(dis[start]+map[start][i]==dis[i])//如果从start点走总路程等于之前的路程 
				 {
				 	ways[i]+=ways[start];//路径总和等于原方案的总数加上新方法的数量 
				 	if(troop[i]+tmax[start]>tmax[i])//判断这种方案是否能够聚集到更多的部队 
				 	{
				 		tmax[i]=troop[i]+tmax[start];//如果能,更新部队 
					 }
				 	
				 }
		 		
		 		
		 			
			 }
		 	
		 	
		 	
		 	
		 }
	 }
	 
	 
	 
	 cout<<ways[c2]<<" "<<tmax[c2];//打印 
	 
	 
	 
} 

 注意点1

vector的开法,经过查阅书籍后发现vector是一种十分高效频繁使用的容器,学会它很重要

格式为:

vector<类型> 名字(长度,数值);//开一个一维

vector<bool> visited(500,false);//开一个一维 

格式为:

vector<vector<int>> map(500,一维的格式);//用来开一个二维数组 

vector<vector<int>> map(500,vector<int>(500,INF));//用来开一个二维数组 

vector目前我发现的主要优点是可以像顺序表一样进行增删查改,并且可以直接初始化你想要的数值。

注意点2

dijkstra算法更新节点的算法十分重要,需要背出

         for(int i=0;i<m;i++)//寻找从start点出发可到达的i边 
         {
             if(!visited[i]&&map[start][i]!=INF)//未被访问且start和i直接存在路径联通 
             {
                 
               if(dis[start]+map[start][i]<dis[i])//如果从start点走总路程小于之前的路程 
               dis[i]=dis[start]+map[start][i];//更新 
             //说明这条路是当前最短路径,需要更新 
           
             }

         }
     

注意点3

#include<climits>
using namespace std;

#define INF INT_MAX //定义int的最大值 

 

这其中的climits用于定义int的最大值,最为无穷大的代名词

 

最后附上我自己的测试数据:

暂时未回到宿舍,数据保存在自己的电脑

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值