写这个题解并没有太大意义。。只是给需要用到的同学写的。
题意比较直:
给予一个地图,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();
}
写代码最好还是稳一些。就算麻烦一些,但是可以避免一些逻辑上可能出现的错误。但是如果是时间复杂度上的问题。。。
不要怂就是干
当然,如果水平够高就不用太在意了。