PAT甲级1111 Online Map

写这个题解并没有太大意义。。只是给需要用到的同学写的。

题意比较直:

给予一个地图,N个点M条路,每条路有对应的时间和长度。最后给出终点和起点,求长度最短(如果存在多条长度最短的路线,求用时最少那条,保证此答案唯一)的路线和时间最短(如果存在多条时间最短的路线,求通过点最少的那条,保证此答案唯一)的路线。保证终点和起点之间至少存在一条路径。

那么就没啥好说的了,一个广搜就可以解决,不过题目要求比较多,那就分成两次求,一次求长度最短,一次求时间最短。

然后题目最后要求输出路径。那就给每个点增加一个Fat数组,用于保存其最佳的上一节点。

例如求长度最短:

SLenth [ i ] 用于存储从起点出发到达 i 节点所需最短的长度,STime [ i ] 用于存储从起点出发到 i 节点所需最短时间,当我们进行广搜时,只要判断下一个点是否满足这两个要求其中一个。

1.现处位置与起点距离+路径长度<目的地位置与起点距离。

2.现处位置与起点距离+路径长度=目的地位置与起点距离  且  到达现处位置时间+路径时间<到达目的地位置时间。

那么我们就可以更新目的地点数据(如父亲节点,距起点距离,距起点时间),并将其加入队列。

时间最短同上处理即可。


参考代码:


#include <stdio.h>

const int MAXM = 510;
const int Size = 1100000;
const int INF = 0x3f3f3f3f;

int Num,Road;
int Begin,Final;

int Total;
int End[MAXM];
int Last[MAXM*MAXM];
int To[MAXM*MAXM];
int Lenth[MAXM*MAXM];
int Times[MAXM*MAXM];

void Add(int u,int v,int lenth,int times)
{
	To[Total]=v;
	Lenth[Total]=lenth;
	Times[Total]=times;
	Last[Total]=End[u];
	End[u]=Total++;
}

void Init()
{
	Total=0;
	for(int i=0;i<Num;i++)
	{
		End[i]=-1;
	}
}

void Read_Case()
{
	scanf("%d %d",&Num,&Road);
	Init();
	int u,v,one,lenth,times;
	for(int i=1;i<=Road;i++)
	{
		scanf("%d %d %d %d %d",&u,&v,&one,&lenth,×);
		Add(u,v,lenth,times);
		if(!one)
		{
			Add(v,u,lenth,times);
		}
	}
	scanf("%d %d",&Begin,&Final);
}

int SLenth[MAXM];
int STime[MAXM];
int SFat[MAXM];
int SList[MAXM];
int SAll;

int FTime[MAXM];
int FFat[MAXM];
int FBest[MAXM];
int FList[MAXM];
int FAll;

int Stack[Size];

bool Judge_S(int now,int To,int lenth,int times)
{
	if(SLenth[now]+lenth<SLenth[To]||(SLenth[now]+lenth==SLenth[To]&&STime[now]+times<STime[To]))
	{
		SLenth[To]=SLenth[now]+lenth;
		STime[To]=STime[now]+times;
		SFat[To]=now;
		return 1;
	}
	return 0;
}

void BFS_S()
{
	int now=Begin;
	int Left=0,Right=0;
	Stack[Right++]=now;
	while(Left<Right)
	{
		now=Stack[Left++];
		int pos=End[now],G;
		while(~pos)
		{
			G=To[pos];
			if(Judge_S(now,G,Lenth[pos],Times[pos]))
			{
				Stack[Right++]=G;
			}
			pos=Last[pos];
		}
	}
}

bool Judge_F(int now,int To,int times)
{
	if(FTime[now]+times<FTime[To]||(FTime[now]+times==FTime[To]&&FBest[now]+1<FBest[To]))
	{
		FTime[To]=FTime[now]+times;
		FBest[To]=FBest[now]+1;
		FFat[To]=now;
		return 1;
	}
	return 0;	
}

void BFS_F()
{
	int now=Begin;
	int Left=0,Right=0;
	Stack[Right++]=now;
	while(Left<Right)
	{
		now=Stack[Left++];
		int pos=End[now],G;
		while(~pos)
		{
			G=To[pos];
			if(Judge_F(now,G,Times[pos]))
			{
				Stack[Right++]=G;
			}
			pos=Last[pos];
		}
	}
}

void GetSList()
{
	SAll=0;
	int pos=Final;
	while(~pos)
	{
		SList[SAll++]=pos;
		pos=SFat[pos];
	}
}

void GetFList()
{
	FAll=0;
	int pos=Final;
	while(~pos)
	{
		FList[FAll++]=pos;
		pos=FFat[pos];
	}
}

bool JudgeEqual()
{
	bool flag=1;
	for(int i=0;i<SAll;i++)
	{
		if(FList[i]!=SList[i])
		{
			flag=0;
			break;
		}
	}
	return flag;
}

void Deal()
{
	for(int i=0;i<Num;i++)
	{
		SLenth[i]=INF;
		STime[i]=INF;
		SFat[i]=-1;
	}
	SLenth[Begin]=STime[Begin]=0;
	BFS_S();
	for(int i=0;i<Num;i++)
	{
		FTime[i]=INF;
		FBest[i]=INF;
		FFat[i]=-1;
	}
	FTime[Begin]=FBest[Begin]=0;
	BFS_F();
	GetSList();
	GetFList();
	if(SAll==FAll&&JudgeEqual())
	{
		printf("Distance = %d; Time = %d:",SLenth[Final],STime[Final]);
		for(int i=SAll-1;i;i--)
		{
			printf(" %d ->",SList[i]);
		}
		printf(" %d\n",SList[0]);
	}
	else
	{
		printf("Distance = %d:",SLenth[Final]);
		for(int i=SAll-1;i;i--)
		{
			printf(" %d ->",SList[i]);
		}
		printf(" %d\n",SList[0]);
		printf("Time = %d:",FTime[Final]);
		for(int i=FAll-1;i;i--)
		{
			printf(" %d ->",FList[i]);
		}
		printf(" %d\n",FList[0]);
	}
}

int main()
{
	Read_Case();
	Deal();
}


写代码最好还是稳一些。就算麻烦一些,但是可以避免一些逻辑上可能出现的错误。但是如果是时间复杂度上的问题。。。

不要怂就是干

当然,如果水平够高就不用太在意了。




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值