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];
}
}