SDUTOJ 2021级ACM班&2022年寒假集训《数据结构》专题10--最短路
A - 图结构练习——最短路径
dijkstra朴素版和堆优化版的模板,权当复习了
因为是循环输入,一开始写初始化函数的时候没有把head和vis也初始化掉,导致TLE了。
左朴素版,右优化版
朴素版:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,cnt,cur; 4 int head[210]; 5 int dis[210]; 6 bool vis[210]; 7 8 struct node 9 { 10 int v,w,next; 11 } edge[100000]; 12 13 void add(int u,int v,int w) 14 { 15 edge[++cnt].v=v; 16 edge[cnt].w=w; 17 edge[cnt].next=head[u]; 18 head[u]=cnt; 19 } 20 21 void init(int n) 22 { 23 for(int i=1; i<=n; i++) 24 { 25 dis[i]=INT_MAX; 26 head[i]=0; 27 vis[i]=0; 28 } 29 dis[1]=0; 30 cur=1; 31 cnt=0; 32 } 33 34 void dijkstra(int n) 35 { 36 for(int i=head[1]; i!=0; i=edge[i].next) 37 dis[edge[i].v]=min(dis[edge[i].v],edge[i].w); 38 while(!vis[cur]) 39 { 40 vis[cur]=true; 41 for(int i=head[cur]; i!=0; i=edge[i].next) 42 { 43 if(!vis[edge[i].v] && dis[edge[i].v]>dis[cur]+edge[i].w) 44 dis[edge[i].v]=dis[cur]+edge[i].w; 45 } 46 int minn=INT_MAX; 47 for(int i=1; i<=n; i++) 48 { 49 if(!vis[i] && dis[i]<minn) 50 { 51 minn=dis[i]; 52 cur=i; 53 } 54 } 55 } 56 cout<<dis[n]<<endl; 57 } 58 59 int main() 60 { 61 while(cin>>n>>m) 62 { 63 init(n); 64 if(m!=0) 65 { 66 for(int i=1; i<=m; i++) 67 { 68 int u,v,w; 69 cin>>u>>v>>w; 70 add(u,v,w); 71 add(v,u,w); 72 } 73 dijkstra(n); 74 } 75 else cout<<"0"<<endl; 76 } 77 return 0; 78 }
优化版:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,cnt,cur; 4 int head[20010]; 5 int dis[20010]; 6 bool vis[20010]; 7 priority_queue< pair<int,int>,vector< pair<int,int> >,greater<pair<int,int> > >q; 8 9 struct node 10 { 11 int v,w,next; 12 }edge[1000010]; 13 14 void add(int u,int v,int w) 15 { 16 edge[++cnt].v=v; 17 edge[cnt].w=w; 18 edge[cnt].next=head[u]; 19 head[u]=cnt; 20 } 21 22 void init(int n) 23 { 24 for(int i=1; i<=n; i++) 25 { 26 dis[i]=INT_MAX; 27 head[i]=0; 28 vis[i]=0; 29 } 30 dis[1]=0; 31 cnt=0; 32 } 33 34 void dijkstra(int n) 35 { 36 q.push(make_pair(0,1)); 37 while(!q.empty()) 38 { 39 int point=q.top().second; 40 q.pop(); 41 if(vis[point]) continue; 42 vis[point]=1; 43 for(int i=head[point]; i!=0; i=edge[i].next) 44 { 45 if(dis[edge[i].v]>dis[point]+edge[i].w) 46 { 47 dis[edge[i].v]=dis[point]+edge[i].w; 48 q.push(make_pair(dis[edge[i].v],edge[i].v)); 49 } 50 } 51 } 52 cout<<dis[n]<<endl; 53 } 54 55 int main() 56 { 57 while(cin>>n>>m) 58 { 59 init(n); 60 for(int i=1; i<=m; i++) 61 { 62 int u,v,w; 63 cin>>u>>v>>w; 64 add(u,v,w); 65 add(v,u,w); 66 } 67 dijkstra(n); 68 } 69 return 0; 70 }
B - 最短路径问题
题目链接 https://acm.sdut.edu.cn/onlinejudge3/contests/3988/problems/B
n<=100,用floyd就可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 double mapp[150][150]; 5 int mapx[150],mapy[150]; 6 void floyd() 7 { 8 for(int k=1; k<=n; k++) 9 { 10 for(int i=1; i<=n; i++) 11 { 12 for(int j=1; j<=n; j++) 13 { 14 if(mapp[i][j]>mapp[i][k]+mapp[k][j]) 15 mapp[i][j]=mapp[i][k]+mapp[k][j]; 16 } 17 } 18 } 19 } 20 21 int main() 22 { 23 cin>>n; 24 for(int i=1; i<=n; i++) 25 { 26 for(int j=1; j<=n; j++) 27 { 28 mapp[i][j]=i==j?0:INT_MAX; 29 } 30 } 31 for(int i=1; i<=n; i++) 32 cin>>mapx[i]>>mapy[i]; 33 cin>>m; 34 for(int i=1; i<=m; i++) 35 { 36 int u,v; 37 double w; 38 cin>>u>>v; 39 w=sqrt((double)(mapx[v]-mapx[u])*(double)(mapx[v]-mapx[u])+(double)(mapy[v]-mapy[u])*(double)(mapy[v]-mapy[u])); 40 if(mapp[u][v]>w) mapp[u][v]=mapp[v][u]=w; 41 } 42 floyd(); 43 int s,t; 44 cin>>s>>t; 45 printf("%.2lf\n",mapp[s][t]); 46 return 0; 47 }
C - C--最短路
题目链接 https://acm.sdut.edu.cn/onlinejudge3/contests/3988/problems/C
用的dijkstra堆优化版
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,s,e; 4 int cnt; 5 int head[500050]; 6 int dis[500050]; 7 bool vis[500050]; 8 priority_queue< pair<int,int>,vector< pair<int,int> >,greater<pair<int,int> > >q; 9 10 struct node 11 { 12 int v,w,next; 13 }edge[5000500]; 14 15 void add(int u,int v,int w) 16 { 17 edge[++cnt].v=v; 18 edge[cnt].w=w; 19 edge[cnt].next=head[u]; 20 head[u]=cnt; 21 } 22 23 void init(int n) 24 { 25 for(int i=1; i<=n; i++) 26 { 27 dis[i]=INT_MAX; 28 vis[i]=0; 29 head[i]=0; 30 } 31 cnt=0; 32 } 33 34 void dijkstra(int s,int e) 35 { 36 dis[s]=0; 37 q.push(make_pair(0,s)); 38 while(!q.empty()) 39 { 40 int point=q.top().second; 41 q.pop(); 42 if(vis[point]) continue; 43 vis[point]=1; 44 for(int i=head[point]; i!=0; i=edge[i].next) 45 { 46 if(dis[edge[i].v]>dis[point]+edge[i].w) 47 { 48 dis[edge[i].v]=dis[point]+edge[i].w; 49 q.push(make_pair(dis[edge[i].v],edge[i].v)); 50 } 51 } 52 } 53 cout<<dis[e]<<endl; 54 } 55 56 int main() 57 { 58 while(cin>>n>>m) 59 { 60 init(n); 61 for(int i=1; i<=m; i++) 62 { 63 int u,v,w; 64 cin>>u>>v>>w; 65 add(u,v,w); 66 add(v,u,w); 67 } 68 cin>>s>>e; 69 dijkstra(s,e); 70 } 71 return 0; 72 }
D - 最短路径(更于——5.9 21:45)
我真服了这个老六啊......调试了整整一个下午都不对,都快给电脑砸了。晚上寻思着写完论文怎么今晚也给整出来吧,结果刚才发现第50行定义 w 忘记用 long long ,服了我真。
这个题,在上面那个题的基础上多了判断是否为x倍数。大体思路是用 SPFA ,增加一个维度,储存步数对 x 取模,最后输出对 x 取模后是 0 的终点距离即可。
1 #include<bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int T,n,m,s,t,x,cnt; 5 int head[110]; 6 long long dis[110][12]; 7 bool vis[110]; 8 queue<int>q; 9 10 struct node 11 { 12 int v; 13 long long w; 14 int next; 15 } edge[10010]; 16 17 void add(int u,int v,long long w) 18 { 19 edge[++cnt].v=v; 20 edge[cnt].w=w; 21 edge[cnt].next=head[u]; 22 head[u]=cnt; 23 } 24 25 void init(int n) 26 { 27 cnt=0; 28 memset(head,0,sizeof(head)); 29 memset(vis,0,sizeof(vis)); 30 for(int i=0; i<=n; i++) 31 for(int j=0; j<=11; j++) 32 dis[i][j]=INF; 33 } 34 35 void spfa() 36 { 37 while(!q.empty()) 38 q.pop(); 39 vis[s]=1; 40 dis[s][0]=0; 41 q.push(s); 42 while(!q.empty()) 43 { 44 int u=q.front(); 45 q.pop(); 46 vis[u]=0; 47 for(int i=head[u]; i!=0; i=edge[i].next) 48 { 49 int v=edge[i].v; 50 long long w=edge[i].w; 51 for(int j=0; j<x; j++) 52 { 53 if(dis[u][j]!=INF && (dis[v][(j+1)%x]>dis[u][j]+w || dis[v][(j+1)%x]==INF)) 54 { 55 dis[v][(j+1)%x]=dis[u][j]+w; 56 if(!vis[v]) 57 { 58 vis[v]=1; 59 q.push(v); 60 } 61 } 62 } 63 } 64 } 65 if(dis[t][0]==INF) cout<<"No Answer!"<<endl; 66 else cout<<dis[t][0]<<endl; 67 } 68 69 int main() 70 { 71 cin>>T; 72 while(T--) 73 { 74 cin>>n>>m; 75 init(n); 76 for(int i=1; i<=m; i++) 77 { 78 int u,v; 79 long long w; 80 cin>>u>>v>>w; 81 add(u,v,w); 82 } 83 cin>>s>>t>>x; 84 spfa(); 85 } 86 return 0; 87 }
E - 数据结构实验之图论七:驴友计划(更于——5.10)
题目链接 https://acm.sdut.edu.cn/onlinejudge3/contests/3988/problems/E
2<=N<=500 ,最喜欢用floyd了!
多定义一个 value 数组保存过路费就好了。
1 #include<bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n,m,s,d; 5 int gra[510][510]; 6 int value[510][510]; 7 8 void floyd() 9 { 10 for(int k=0; k<n; k++) 11 { 12 for(int i=0; i<n; i++) 13 { 14 for(int j=0; j<n; j++) 15 { 16 if(i!=j) 17 { 18 if(gra[i][j]>gra[i][k]+gra[k][j]) 19 { 20 gra[i][j]=gra[i][k]+gra[k][j]; 21 value[i][j]=value[i][k]+value[k][j]; 22 } 23 if(gra[i][j]==gra[i][k]+gra[k][j]) 24 { 25 if(value[i][j]>value[i][k]+value[k][j]) 26 value[i][j]=value[i][k]+value[k][j]; 27 } 28 } 29 } 30 } 31 } 32 } 33 34 int main() 35 { 36 int T; 37 cin>>T; 38 while(T--) 39 { 40 cin>>n>>m>>s>>d; 41 for(int i=0; i<n; i++) 42 { 43 for(int j=0; j<n; j++) 44 { 45 if(i==j) gra[i][j]=value[i][j]=0; 46 else gra[i][j]=value[i][j]=INF; 47 } 48 } 49 for(int i=0; i<m; i++) 50 { 51 int u,v,w,val; 52 cin>>u>>v>>w>>val; 53 gra[u][v]=gra[v][u]=w; 54 value[u][v]=value[v][u]=val; 55 } 56 floyd(); 57 cout<<gra[s][d]<<" "<<value[s][d]<<endl; 58 } 59 return 0; 60 }
F - 人活着系列之芳姐和芳姐的猪
题目链接 https://acm.sdut.edu.cn/onlinejudge3/problems/2929
首先看到结点的数据范围 2<=m<=600 ,直接想到 floyd 。然后读题,可以看出是多源最短路问题,需要算出每个点到每个点的最短路,起始点和终点都不固定。
1 #include<bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n,m,k; 5 int s[610]; 6 int mapp[610][610]; 7 8 void floyd() 9 { 10 for(int k=1; k<=m; k++) 11 for(int i=1; i<=m; i++) 12 for(int j=1; j<=m; j++) 13 mapp[i][j]=min(mapp[i][j],mapp[i][k]+mapp[k][j]); 14 } 15 16 int main() 17 { 18 cin>>n>>m>>k; 19 for(int i=1; i<=n; i++) 20 cin>>s[i]; 21 memset(mapp,INF,sizeof(mapp)); 22 for(int i=1; i<=610; i++) 23 mapp[i][i]=0; 24 for(int i=1; i<=k; i++) 25 { 26 int u,v,w; 27 cin>>u>>v>>w; 28 if(w<mapp[u][v]) 29 mapp[u][v]=mapp[v][u]=w; 30 } 31 int minn=INF; 32 floyd(); 33 for(int i=1; i<=m; i++) 34 { 35 int sum=0; 36 for(int j=1; j<=n; j++) 37 { 38 sum+=mapp[i][s[j]]; 39 } 40 if(sum<minn) 41 minn=sum; 42 } 43 cout<<minn<<endl; 44 return 0; 45 }