pat甲级_路径问题(例题:pat 1003 Emergency (25))

pat中常考题之一便是最短路径问题,以我浅显的理解觉得此类问题可以这么描述:
1.求最短路径
2.根据一些题设条件筛选最短路径,得出一条或者是几条合适的
3.输出关于最短路径的一些相关信息,有可能是数量,路径,耗时等等

此类问题会给出的信息:
1.路径信息,用于求解最短路径
2.其他信息,用于筛选已经得到的最短路径,如例题中以救援人员最多这一条件来筛选最短路径
3.需要输出的信息(这点也很重要)

此类问题,一般会用dijkstra和dfs两种常见的手法来求解,具体思路会在例题的解答中给出

Input

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

For each test case, print in one line two numbers: the number of different 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



dfs解法:
解题思路就是利用dfs找出起始点到目的地之间的所有路径,与当前最优路径做比较。在数据量大时运行时间会增加迅速。
#include <stdio.h>
#include <vector>
using namespace std;

const int maxint=-1;                                //-1表示当前路径不存在或当前节点路径信息未被初始化
int N,M,c1,c2;
vector<int> hands;                                  //每个城市救援人员
vector<bool> fl;
vector< vector<int> > roads;                        //保存路径信息
void dfs(int s,int end);                            //深搜函数
int mincost(maxint),maxhand,pathn;            //对应最短用时,最多救援人员,最短路径数
int time,hand;                                //到达当前点的路径时间,救援人员

int main()
{
	scanf("%d %d %d %d",&N,&M,&c1,&c2);
	hands.resize(N);
	fl.resize(N,false);
	fl[c1]=true;
	for(int i=0;i<N;i++) scanf("%d",&hands[i]);
	roads.resize(N,vector<int> (N,maxint));
	for(int i=0;i<M;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		roads[a][b]=c;
		roads[b][a]=c;
	}

	hand=hands[c1];                                      //千万要记得初始化,因为c2=c1的情况下判断会被跳过,测试点2通不过有可能是这个原因
	time=0;
	maxhand=hands[c1];
	pathn=1;

	dfs(c1,c2);
	printf("%d %d",pathn,maxhand);
	return 0;
}
void dfs(int s,int e)
{
	for(int i=0;i<N;i++)
	{	
		if(roads[s][i]!=maxint&&!fl[i])                       //注意:c2=c1的情况下,判断会被跳过
		{
			if(time>mincost&&mincost!=maxint) break;      //时间已超过mincost
			time+=roads[s][i];                            
			hand+=hands[i];
			fl[i]=true;
			if(i==e)                                      //到终点时对路径信息进行判断
			{
				if(time<mincost||mincost==maxint) 
				{
					mincost=time;
					maxhand=hand;
					pathn=1;
				}
				else
				{
					if(time==mincost)
					{
						pathn++;
						if(maxhand<hand) maxhand=hand;
					}
				}
			}
			else dfs(i,e);

			time-=roads[s][i];                          //释放该路径的信息
			hand-=hands[i];
			fl[i]=false;
		}
	}
}


dijkstra回溯解法:

首先由dj算法求出最短路径的所有可能取值,之后通过回溯计算考虑筛选路径的条件,给出最适合的一条路径,得到题目中要求的输出信息。在输出信息中要求输出path时可以将每次比较最符合筛选条件的前置点加入path,然后递归。

#include <stdio.h>
#include <vector>

using namespace std;
const int maxint=-1;
int N,M,c1,c2;
vector<int> hands;
vector< vector<int> > roads;
vector< vector<int> > pre;
void dijkstra(int s,int e);  
int dfs(int e);              
int pathn;

int main()
{
	scanf("%d %d %d %d",&N,&M,&c1,&c2);
	pre.resize(N);
	hands.resize(N);
	for(int i=0;i<N;i++) scanf("%d",&hands[i]);
	roads.resize(N,vector<int> (N,maxint));
	for(int i=0;i<M;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		roads[a][b]=c;
		roads[b][a]=c;
	}
	dijkstra(c1,c2);
	int hand;
	hand=dfs(c2);

	printf("%d %d",pathn,hand);
	return 0;
}

void dijkstra(int s,int e)                                                                   
{
	vector<int> dist(N,maxint);
	vector<bool> fl(N,false);

	fl[s]=true;
	dist[s]=0;
	pre[s].push_back(-1);
	int u=s;
	while(!fl[e])
	{
		for(int i=0;i<N;i++)
		{
			if(!fl[i]&&roads[u][i]!=maxint)
			{
				int newdist=roads[u][i]+dist[u];
				if(dist[i]==maxint||dist[i]>newdist)
				{
					dist[i]=newdist;
					if(!pre.empty()) pre[i].clear();
					pre[i].push_back(u);
				}
				else{ if(dist[i]==newdist) pre[i].push_back(u); }
			}
		}

		int tmp=maxint;
		for(int i=0;i<N;i++)
		{
			if(!fl[i]&&dist[i]!=maxint)
			{
				if(dist[i]<tmp||tmp==maxint)
				{
					tmp=dist[i];
					u=i;
				}
			}
		}
		fl[u]=true;
	}
}

int dfs(int e)
{
	int u=e;
	int mhand(0);
	if(pre[u][0]==-1) 
	{
		pathn++;                                               //每次回溯至起点,路径值+1
		return hands[u];
	}
	for(int i=0;i<pre[u].size();i++)     
	{
		int hand=hands[u]+dfs(pre[u][i]);
		if(hand>mhand) mhand=hand;                            //找出人数最多的一条路径,如果要得出路径,可以在这里将前置点push_back
	}
	return mhand;
}


dijkstra解法:

此解法首先需要的是创建一个存储有用节点信息的结构,必不可少的结构是bool fl作为该点路径是否确定的标志位以及int cost 最短时间。根据题设还需要添加的是int hand 救援人数, int pathn 最短路径数。解题思路是每次dj更新最少耗时的同时更新未确定节点的相关信息,当到达目标点时,需要输出的信息已经更新为最符合题设的形式,由于减少了回溯的过程,运行用时有所提高。在输出结果要求输出path时,可以将符合规定的前置节点索引加入节点结构中。

#include <stdio.h>
#include <vector>
using namespace std;

const int maxint=-1;
int N,M,c1,c2;
vector<int> hands;
vector< vector<int> > roads;

struct node
{
	bool fl;
	int cost;           //最少耗时
	int hand;           //救援人员            
	int pathn;          //路径数
};
vector<node> cn;
void dijkstra(int s,int e);

int main()
{
	scanf("%d %d %d %d",&N,&M,&c1,&c2);
	hands.resize(N);
	for(int i=0;i<N;i++) scanf("%d",&hands[i]);
	roads.resize(N,vector<int> (N,maxint));
	for(int i=0;i<M;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		roads[a][b]=c;
		roads[b][a]=c;
	}

	node nodei;
	nodei.cost=maxint;
	nodei.fl=false;
	nodei.hand=0;
	nodei.pathn=0;
	cn.resize(N,nodei);

	dijkstra(c1,c2);
	printf("%d %d",cn[c2].pathn,cn[c2].hand);
	return 0;
}

void dijkstra(int s,int e)
{
	cn[s].fl=true;
	cn[s].cost=0;
	cn[s].hand=hands[c1];
	cn[s].pathn=1;

	int u=s;
	while(!cn[e].fl)
	{
		for(int i=0;i<N;i++)
		{
			if(!cn[i].fl&&roads[u][i]!=maxint)
			{
				int newdist=roads[u][i]+cn[u].cost;
				if(newdist<cn[i].cost||cn[i].cost==maxint)            //求当前最短路径
				{
					cn[i].cost=newdist;
					cn[i].pathn=cn[u].pathn;
					cn[i].hand=cn[u].hand+hands[i];
				}
				else 
				{
					if(newdist==cn[i].cost)                            //路径相等时比较救援人数,最后一个测试点通不过的原因
					{
						cn[i].pathn+=cn[u].pathn;
						int newhand=cn[u].hand+hands[i];
						if(newhand>cn[i].hand) cn[i].hand=newhand;
					}
				}
			}
		}
		int tmp(maxint);
		for(int i=0;i<N;i++)
		{
			if(!cn[i].fl&&cn[i].cost!=maxint)
			{
				if(tmp==maxint||tmp>cn[i].cost)
				{
					tmp=cn[i].cost;
					u=i;
				}
			}
		}
		cn[u].fl=true;
	}
}





最后,一些带注意注释是我刷题时出现错误的点(希望能够帮助到同样在准备pat考试的同学),有的时候debug显得比写代码更加重要,可能就是因为对边界情况考虑不足或是一些其他原因导致测试点通不过往往会纠结很长时间,因此在这里非常感谢我可爱的弟弟蒋小家同学帮我找出这些错误。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值