【2019寒假集训DAY2】最短路
Dijkstra
- 条件:无负权;时间:O(n*n)
- 详解+模板: https://www.cnblogs.com/jason2003/p/7222182.html
- (模板)P1821 [USACO07FEB]银牛派对Silver Cow Party:https://www.luogu.org/recordnew/show/12339877
-
void dj(){ for(int i=1;i<=m;i++) if(i!=k)dis[i]=M; for(int i=1;i<=m;i++){ int min=M; for(int j=1;j<=m;j++) if(b[j]==0&&dis[j]<min){ min=dis[j]; t=j; } b[t]=1; if(t==s)return; for(int j=1;j<=m;j++) if(b[j]==0&&a[t][j]>0&&dis[j]>dis[t]+a[t][j]){ dis[j]=dis[t]+a[t][j]; } } }
- 步骤:
- dis[i]记录到源点距离; vis[i]判断被标记否;a[u][v]=w;
- 初始化:源点为0,其他点inf
- 选择并标记k点:选择未被标记的k点,d[k]最小;vis[k]=1;
- 修改其他未标记、过k点点j到源点距离:vis[j]=0&&a[u][v]>0&&dis[j]>dis[k]+a[k][j];
- 堆优化
Floyd
- 条件:无负环;时间:O(n*n*n);DP思想
- (模板)P1346 电车:https://www.luogu.org/problemnew/show/P1346
- 模板
- 初始化:s[i][i]=0;s[i][j]读入;(根据题可能有改动,电车就设为要下车改变路线则=1,不用=0)
- 三层循环,k在最外层;s[i][j]>s[i][k]+s[k][j]
for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i!=j) s[i][j]=M; } } for(int i=1;i<=n;i++){ cin>>x; for(int j=1;j<=x;j++){ cin>>y; if(j==1) s[i][y]=0; else s[i][y]=1; } } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(s[i][j]>s[i][k]+s[k][j]){ s[i][j]=s[i][k]+s[k][j]; } } } }
- Floyd求最小环
-
#10072. 「一本通 3.2 例 1」Sightseeing Trip:https://loj.ac/problem/10072
- 附STL中vector用法:vector<ll>path; path.clear();path.push_back(i);path.size()path[i]
- 附memcpy用法:memcpy(mp,dist,sizeof(dist));
- 附代码
#include <bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f using namespace std; ll n,m,dist[200][200],mp[200][200],huan[200][200],x,y,z,len=inf; vector<ll>path; void get(ll x,ll y){ if(huan[x][y]==0)return; get(x,huan[x][y]); path.push_back(huan[x][y]); get(huan[x][y],y); } int main() { cin>>n>>m; memset(dist,inf,sizeof(dist)); for(ll i=1;i<=n;i++)dist[i][i]=0; for(ll i=1;i<=m;i++){ cin>>x>>y>>z; dist[x][y]=dist[y][x]=min(dist[x][y],z); } memcpy(mp,dist,sizeof(dist)); for(ll k=1;k<=n;k++){ for(ll i=1;i<k;i++){ for(ll j=i+1;j<k;j++){ if(len>dist[i][j]+mp[i][k]+mp[k][j]){ len=dist[i][j]+mp[i][k]+mp[k][j]; path.clear(); path.push_back(i); get(i,j); path.push_back(j); path.push_back(k); } } } for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ if(dist[i][j]>dist[i][k]+dist[k][j]){ dist[i][j]=dist[i][k]+dist[k][j]; huan[i][j]=huan[j][i]=k; } } } } //先更新最小环再更新最短路:否则dist[i][j]会改变 //无向图对称性:j从i+1开始 //i、j<k:https://www.cnblogs.com/zzqc/p/6855913.html if(len==inf)cout<<"No solution."; else{ for(ll i=0;i<path.size();i++) { cout<<path[i]<<" "; } } return 0; }
5.附有向环:https://vijos.org/p/1423; 代码(直接跑floyd):
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 0x3f3f3f3f int n,m,e[210][210],w[210]; int main(){ cin>>n>>m; memset(e,inf,sizeof(e)); for(ll i=1;i<=n;i++)cin>>w[i]; for(ll i=1;i<=m;i++){ int x,y,z; cin>>x>>y>>z; e[x][y]=min(e[x][y],z+w[x]); } for(ll k=1;k<=n;k++){ for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++){ e[i][j]=min(e[i][j],e[i][k]+e[k][j]); } } } if(e[1][1]==inf)cout<<"-1"; else cout<<e[1][1]; return 0; }