L3 天梯地图
天梯地图题目
当我看到这道题的第一思路是,这道题肯定是用搜索,至于是深搜还是广搜,我选择了深搜。其实对于搜索这类题目,我是比较害怕的,因为最近写搜索的题目写的有点少了,但是,迎难而上的道理我还是懂的,于是我就开始动手敲代码,~~~~~~~~~一段时间以后,我终于写完了这道题的深搜代码,于是我满怀信心的提交了上去,但是,出问题了,一部分样例超时,没关系,肯定是深搜时间复杂度太高了,我换个思路吗,改为广搜一定可以 ~~~~~~~~~有过了一段时间,广搜的代码也被我写好了,这下一定可以了吧,于是我再次满怀信心的提交了广搜的代码,什么,还是超时,这个结果让我很绝望。这下我终于意识到思路错了,哎,最终我还是被困难给打败了,我手动百度了一下,然后crtl c,ctrl v,呀过了,太神奇了吧。作者一道题过程真的是太辛苦了,不由得感慨一下。
进入正题,这道题使用两次dijkstra即可,但是需要稍微改变一下,例如求最快最短的情况下,慢的需要更新为快的毋庸置疑,同时同样快的应该考虑路径长度是否需要更新;下面是这道题的代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5000;
int head[maxn],tot=0;
int s,e,n,m;
const int inf=0x3f3f3f3f;
struct Edge{
int v;
int len,time,next;
}edge[maxn*maxn];
int tt[maxn][maxn],ll[maxn][maxn];
int vis[maxn],len[maxn],pre[maxn],cnt[maxn],t[maxn];
void addedge(int u,int v,int len,int t)
{
edge[tot].v=v;
edge[tot].len=len;
edge[tot].time=t;
edge[tot].next=head[u];
head[u]=tot++;
}
void dijkstra1()
{
fill(vis,vis+maxn,0);
fill(t,t+maxn,inf);
fill(len,len+maxn,inf);
for(int i=0;i<maxn;i++) pre[i]=i;
t[s]=0;
len[s]=0;
pre[s]=s;
for(int i=1;i<=n;i++)
{
int u=-1,Min=inf;
for(int j=0;j<n;j++)
{
if(vis[j]==0&&t[j]<Min)
{
u=j;
Min=t[j];
}
}
vis[u]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(vis[v]) continue;
if(t[v]>t[u]+edge[j].time)
{
t[v]=t[u]+edge[j].time;
len[v]=len[u]+edge[j].len;
pre[v]=u;
}
else if(t[v]==t[u]+edge[j].time&&len[v]>len[u]+edge[j].len)
{
t[v]=t[u]+edge[j].time;
len[v]=len[u]+edge[j].len;
pre[v]=u;
}
}
}
}
void dijkstra2()
{
fill(vis,vis+maxn,0);
fill(len,len+maxn,inf);
fill(cnt,cnt+maxn,inf);
for(int i=0;i<maxn;i++) pre[i]=i;
len[s]=0;
cnt[s]=1;
pre[s]=s;
for(int i=1;i<=n;i++)
{
int u=-1,Min=inf;
for(int j=0;j<n;j++)
{
if(vis[j]==0&&len[j]<Min)
{
u=j;
Min=len[j];
}
}
vis[u]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(vis[v]) continue;
if(len[v]>len[u]+edge[j].len)
{
len[v]=len[u]+edge[j].len;
cnt[v]=cnt[u]+1;
pre[v]=u;
}
else if(len[v]==len[u]+edge[j].len&&cnt[v]>cnt[u]+1)
{
len[v]=len[u]+edge[j].len;
cnt[v]=cnt[u]+1;
pre[v]=u;
}
}
}
}
int main()
{
fill(head,head+maxn,-1);
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,t,len,time;
cin>>u>>v>>t>>len>>time;
if(t)
{
addedge(u,v,len,time);
}
else
{
addedge(u,v,len,time);
addedge(v,u,len,time);
}
}
cin>>s>>e;
int ans=0;
dijkstra1();
// cout<<t[3]<<endl;
int Time=t[e];
int strt[maxn];
int k=e;
while(1)
{
strt[ans++]=k;
if(k==s) break;
k=pre[k];
}
// cout<<str1;
dijkstra2();
int Len=len[e];
int strl[maxn];
int k1=e;
int ans1=0;
while(1)
{
strl[ans1++]=k1;
if(k1==s) break;
k1=pre[k1];
}
// cout<<len[e]<<" "<<str2;
int flag=0;
if(ans==ans1)
{
for(int i=0;i<ans;i++)
{
if(strl[i]!=strt[i])
{
flag=1;
break;
}
}
}
else flag=1;
if(flag==0)
{
printf("Time = %d; ",Time);
printf("Distance = %d: ",Len);
// cout<<"Time = "<<Time<<"; ";
// cout<<"Distance = "<<Len<<": ";
for(int i=ans-1;i>=0;i--)
{
if(i==ans-1)
printf("%d",strt[i]);
//cout<<strt[i];
else
printf(" => %d",strt[i]);
// cout<<" => "<<strt[i];
}
return 0;
}
printf("Time = %d: ",Time);
//cout<<"Time = "<<Time<<": ";
for(int i=ans-1;i>=0;i--)
{
if(i==ans-1)
printf("%d",strt[i]);
//cout<<strt[i];
else
printf(" => %d",strt[i]);
//cout<<" => "<<strt[i];
}
printf("\n");
//cout<<endl;
printf("Distance = %d: ",Len);
// cout<<"Distance = "<<Len<<": ";
for(int i=ans1-1;i>=0;i--)
{
if(i==ans1-1)
printf("%d",strl[i]);
//cout<<strl[i];
else
printf(" => %d",strl[i]);
//cout<<" => "<<strl[i];
}
}
不过上面的代码是我千辛万苦才修改对的,一个bug,找了整整一天
这是错误代码,bug仅仅在因为在输出路径时,我先用string把pre中的数字+‘0’转换为字符保存起来,但是这会有一个问题,就是如果数字大于等于10以后,就会出问题了,大家要以此为戒,千万不要在犯我这种错误了
#include<bits/stdc++.h>
using namespace std;
const int maxn=5000;
int head[maxn],tot=0;
int s,e,n,m;
const int inf=0x3f3f3f3f;
struct Edge{
int v;
int len,time,next;
}edge[maxn*maxn];
int tt[maxn][maxn],ll[maxn][maxn];
int vis[maxn],len[maxn],pre[maxn],cnt[maxn],t[maxn];
void addedge(int u,int v,int len,int t)
{
edge[tot].v=v;
edge[tot].len=len;
edge[tot].time=t;
edge[tot].next=head[u];
head[u]=tot++;
}
void dijkstra1()
{
fill(vis,vis+maxn,0);
fill(t,t+maxn,inf);
fill(len,len+maxn,inf);
for(int i=0;i<maxn;i++) pre[i]=i;
t[s]=0;
len[s]=0;
pre[s]=s;
for(int i=1;i<=n;i++)
{
int u=-1,Min=inf;
for(int j=0;j<n;j++)
{
if(vis[j]==0&&t[j]<Min)
{
u=j;
Min=t[j];
}
}
vis[u]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(vis[v]) continue;
if(t[v]>t[u]+edge[j].time)
{
t[v]=t[u]+edge[j].time;
len[v]=len[u]+edge[j].len;
pre[v]=u;
}
else if(t[v]==t[u]+edge[j].time&&len[v]>len[u]+edge[j].len)
{
t[v]=t[u]+edge[j].time;
len[v]=len[u]+edge[j].len;
pre[v]=u;
}
}
}
}
void dijkstra2()
{
fill(vis,vis+maxn,0);
fill(len,len+maxn,inf);
fill(cnt,cnt+maxn,inf);
for(int i=0;i<maxn;i++) pre[i]=i;
len[s]=0;
cnt[s]=1;
pre[s]=s;
for(int i=1;i<=n;i++)
{
int u=-1,Min=inf;
for(int j=0;j<n;j++)
{
if(vis[j]==0&&len[j]<Min)
{
u=j;
Min=len[j];
}
}
vis[u]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(vis[v]) continue;
if(len[v]>len[u]+edge[j].len)
{
len[v]=len[u]+edge[j].len;
cnt[v]=cnt[u]+1;
pre[v]=u;
}
else if(len[v]==len[u]+edge[j].len&&cnt[v]>cnt[u]+1)
{
len[v]=len[u]+edge[j].len;
cnt[v]=cnt[u]+1;
pre[v]=u;
}
}
}
}
int main()
{
fill(head,head+maxn,-1);
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,t,len,time;
cin>>u>>v>>t>>len>>time;
if(t)
{
addedge(u,v,len,time);
}
else
{
addedge(u,v,len,time);
addedge(v,u,len,time);
}
}
cin>>s>>e;
dijkstra1();
// cout<<t[3]<<endl;
int Time=t[e];
string strt="";
int k=e;
while(1)
{
strt+=(k+'0');
if(k==s) break;
k=pre[k];
}
// cout<<str1;
dijkstra2();
int Len=len[e];
string strl="";
int k1=e;
while(1)
{
strl+=(k1+'0');
if(k1==s) break;
k1=pre[k1];
}
// cout<<len[e]<<" "<<str2;
if(strl==strt)
{
printf("Time = %d; ",Time);
printf("Distance = %d: ",Len);
// cout<<"Time = "<<Time<<"; ";
// cout<<"Distance = "<<Len<<": ";
for(int i=strt.size()-1;i>=0;i--)
{
if(i==strt.size()-1)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
// cout<<" => "<<strt[i];
}
return 0;
}
printf("Time = %d: ",Time);
//cout<<"Time = "<<Time<<": ";
for(int i=strt.size()-1;i>=0;i--)
{
if(i==strt.size()-1)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
//cout<<" => "<<strt[i];
}
printf("\n");
//cout<<endl;
printf("Distance = %d: ",Len);
// cout<<"Distance = "<<Len<<": ";
for(int i=strl.size()-1;i>=0;i--)
{
if(i==strl.size()-1)
printf("%c",strl[i]);
//cout<<strl[i];
else
printf(" => %c",strl[i]);
//cout<<" => "<<strl[i];
}
}
不过,通过做这道题还是有点收获的,因为好久没写搜索的题目了,我自己都快忘记搜索怎么写了,尤其是深搜的如何传参和广搜的队列中储存什么,写完两个代码我发现,深搜dfs函数里面的参数就是通过一步步搜索,你需要的答案(当然在不考虑你定义全局变量的情况下),广搜队列中存储的也是这些答案,这就是他们的相似之处。而且,我总结了一下我以后如何写搜索,
- 首先,判断一下是否搜到了,没搜到了的话就继续搜
- 当然就是继续搜的过程了,继续向下搜的话 首先你要满足可以继续向下搜的条件,比如迷宫问题,你不可以越界,该店没走过、比如这道题,条件是你在搜到这里时这个点没有搜过才可以。
- 再然后你就需要在第二步的基础上注意一下回溯问题了,因为深搜是一条路走到底的过程,哪一条路在前面他就会先走那一条路,因此,之前搜索的不一定时最优的,你需要记录一下,通过比较更新找到最优的。在同一点,有许多条路可以走,你想再走其他路时,你就要清除之前走过路的影响,这就是回溯的时候清除影响,从而使搜的每一条路对应一个vis数组,对应一个这条路你要求的数据。而在广搜中,每一个入队列的结构体就相当于是一条独自的路,所以你只需要在结构体中开一个vis数组和一个记录数据的变量就和深搜的回溯一样了。
而算法笔记上的广搜为什么就不用在结构体内部定义一个vis数组呢,应为那里是让你求最短路径的,你走的下一个节点不仅要你自己没有走过,比别人也要没有走过,不然,你这条路就不是最短的了。而这道天梯地图这道题是按边长的权值和,而不是把每个边的权值看作是1.
我的dfs和bfs代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3;
int head[maxn],tot=0;
int s,e;
struct Edge{
int v;
int len,time,next;
}edge[maxn*maxn];
void addedge(int u,int v,int len,int time)
{
edge[tot].v=v;
edge[tot].len=len;
edge[tot].time=time;
edge[tot].next=head[u];
head[u]=tot++;
}
string strl="";
int Len=99999999;
string strt="";
int lent=99999;
int Time=99999999;
class node{
public:
int x;
string str;
int len,time;
int vis[maxn];
node()
{
fill(vis,vis+maxn,0);
}
};
void bfs()
{
queue<node>q;
node t;
t.x=s;
t.len=0;
t.time=0;
t.str=s+'0';
q.push(t);
t.vis[s]=1;
while(!q.empty())
{
t=q.front();
q.pop();
if(t.x==e)
{
if(t.time<Time||t.time==Time&&t.len<lent)
{
strt=t.str;
Time=t.time;
lent=t.len;
}
if(t.len<Len||Len==t.len&&strl.size()>t.str.size())
{
Len=t.len;
strl=t.str;
}
}
int x=t.x;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(t.vis[v]==0)
{
node t1;
t1=t;
t1.str+=('0'+v);
t1.time+=edge[i].time;
t1.len+=edge[i].len;
t1.x=v;
t1.vis[v]=1;
q.push(t1);
// dfs(v,ss,len+edge[i].len,time+edge[i].time);
}
}
}
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int n,m;
fill(head,head+maxn,-1);
scanf("%d%d",&n,&m);
// cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v,t,len,time;
cin>>u>>v>>t>>len>>time;
if(t)
{
addedge(u,v,len,time);
}
else
{
addedge(u,v,len,time);
addedge(v,u,len,time);
}
}
string str="";
cin>>s>>e;
str+=(s+'0');
bfs();
if(strl==strt)
{
printf("Time = %d; ",Time);
printf("Distance = %d: ",Len);
// cout<<"Time = "<<Time<<"; ";
// cout<<"Distance = "<<Len<<": ";
for(int i=0;i<strt.size();i++)
{
if(i==0)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
// cout<<" => "<<strt[i];
}
return 0;
}
printf("Time = %d: ",Time);
//cout<<"Time = "<<Time<<": ";
for(int i=0;i<strt.size();i++)
{
if(i==0)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
//cout<<" => "<<strt[i];
}
printf("\n");
//cout<<endl;
printf("Distance = %d: ",Len);
// cout<<"Distance = "<<Len<<": ";
for(int i=0;i<strl.size();i++)
{
if(i==0)
printf("%c",strl[i]);
//cout<<strl[i];
else
printf(" => %c",strl[i]);
//cout<<" => "<<strl[i];
}
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3;
int head[maxn],tot=0;
int s,e;
struct node{
int v;
int len,time,next;
}edge[maxn*maxn];
void addedge(int u,int v,int len,int time)
{
edge[tot].v=v;
edge[tot].len=len;
edge[tot].time=time;
edge[tot].next=head[u];
head[u]=tot++;
}
string strl="";
int Len=99999999;
string strt="";
int lent=99999;
int Time=99999999;
int vis[maxn];
void dfs(int x,string str,int len,int time)
{
if(x==e)
{
// cout<<str<<" len "<<len<<" time "<<time<<endl;
if(time<Time||time==Time&&len<lent)
{
strt=str;
Time=time;
lent=len;
}
if(len<Len||Len==len&&strl.size()>str.size())
{
Len=len;
strl=str;
}
}
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(vis[v]==0)
{
string ss=str;
ss+=('0'+v);
vis[v]=1;
dfs(v,ss,len+edge[i].len,time+edge[i].time);
vis[v]=0;
}
}
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int n,m;
fill(head,head+maxn,-1);
scanf("%d%d",&n,&m);
// cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v,t,len,time;
cin>>u>>v>>t>>len>>time;
if(t)
{
addedge(u,v,len,time);
}
else
{
addedge(u,v,len,time);
addedge(v,u,len,time);
}
}
string str="";
cin>>s>>e;
str+=(s+'0');
vis[s]=1;
dfs(s,str,0,0);
if(strl==strt)
{
printf("Time = %d; ",Time);
printf("Distance = %d: ",Len);
// cout<<"Time = "<<Time<<"; ";
// cout<<"Distance = "<<Len<<": ";
for(int i=0;i<strt.size();i++)
{
if(i==0)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
// cout<<" => "<<strt[i];
}
return 0;
}
printf("Time = %d: ",Time);
//cout<<"Time = "<<Time<<": ";
for(int i=0;i<strt.size();i++)
{
if(i==0)
printf("%c",strt[i]);
//cout<<strt[i];
else
printf(" => %c",strt[i]);
//cout<<" => "<<strt[i];
}
printf("\n");
//cout<<endl;
printf("Distance = %d: ",Len);
// cout<<"Distance = "<<Len<<": ";
for(int i=0;i<strl.size();i++)
{
if(i==0)
printf("%c",strl[i]);
//cout<<strl[i];
else
printf(" => %c",strl[i]);
//cout<<" => "<<strl[i];
}
}