区队A 最短路1
复杂度
\(O(n + m\cdot log \cdot n)\)
模板:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 1e5+10;
int dis[N];
bool vis[N];
int n,m;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int s;
cin>>n >> m >> s;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
// e[v].push_back({u,w});
}
dijkstra(s);
for(int i = 1;i<=n;i++)
{
cout<<dis[i]<<' ';
}
return 0;
}
小优化
在遇到重复元素进队时,可以考虑使用zkw线段树->非递归线段树,进行一个点修区查的优化
P4779 【模板】单源最短路径(标准版)
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 1e5+10;
int dis[N];
bool vis[N];
int n,m;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int s;
cin>>n >> m >> s;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
// e[v].push_back({u,w});
}
dijkstra(s);
for(int i = 1;i<=n;i++)
{
cout<<dis[i]<<' ';
}
return 0;
}
P2984 [USACO10FEB] Chocolate Giving S
注意到,\(p\)要先到1节点然后从1节点去往\(q\),所以显然的,先跑一次以1为起点的dijkstra,然后用公式\(ans = dis[p] + dis[q]\)就可以显而易见地解决了
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 1e5+10;
int dis[N];
bool vis[N];
int n,m;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int b;
cin>>n >> m >> b;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dijkstra(1);
while(b--)
{
int q,p;
cin>>p>>q;
cout<<dis[p] + dis[q]<<'\n';
}
return 0;
}
P1629 邮递员送信
考虑建反向边,即可完成
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 1e5+10;
int dis[N];
bool vis[N];
int n,m;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int b;
cin>>n >> m;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v == 1 ? v : v + n].push_back({u+n,w});
}
dijkstra(1);
int ans = 0;
for(int i = 2;i<=n;i++)
{
ans += dis[i];
}
// dijkstra(1 + n);
for(int i = 2 + n;i <= n<<1;i++)
{
ans += dis[i];
}
cout<<ans;
return 0;
}
同样的,floyd可以卡过去
#include <bits/stdc++.h>
using namespace std;
int n,m,dis[1005][1005];
signed main(){
memset(dis,0x3f,sizeof(dis));
cin>>n>>m;
for(int i=1,x,y,z;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
dis[x][y]=min(dis[x][y],z);
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
int ans=0;
for(int i=2;i<=n;++i)
ans+=(dis[i][1]+dis[1][i]);
printf("%d\n",ans);
}
P1462 通往奥格瑞玛的道路
最大最小值那我们就二分答案,通过枚举答案反推
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 1e5+10;
int dis[N];
bool vis[N];
int n,m,b;
vector<pii> e[N];
int f[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
bool dijkstra(int s,int x)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(f[v] <= x && dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}return dis[n] <= b;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin>>n >> m>>b;
// int maxn = 0,minn = 0x3f3f3f3f;
for(int i= 1;i<=n;i++)
{
cin>>f[i];
// maxn = max(maxn,f[i]);
// minn = min(minn,f[i]);
}
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
// sort(f+1,f+n+1);
int l = max(f[1],f[n]),r = 1e9,ans = -1;
while(l <= r)
{
int mid = (l + r) >> 1;
if(dijkstra(1,mid))
{
ans = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
if(ans == -1)
{
cout<<"AFK";
}
else{
cout<<ans;
}
return 0;
}
P2446 [SDOI2010] 大陆争霸
约束上最短路
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int INF = 0x3f3f3f3f3f3f3f3fll;
const int N = 3010;
int dis[N];
//int ans[N];
int in_degree[N];
vector<int> gen[N];
bool vis[N];
int n,m;
vector<pii> e1[N];
vector<int> e2[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
// vis[s] = 1;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e1[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(in_degree[v] ==0)
q.push({dis[v],v});
}
}for(int v : e2[u])
{
--in_degree[v];
dis[v] = max(dis[v],dis[u]);
if(in_degree[v] == 0)
{
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int s;
cin>>n >> m;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e1[u].push_back({v,w});
// e[v].push_back({u,w});
}
for(int i = 1;i<=n;i++)
{
cin>>in_degree[i];
for(int j= 1;j<=in_degree[i];j++)
{
int v;
cin>>v;
e2[v].push_back(i);
}
}
dijkstra(1);
cout<<dis[n];
return 0;
}
P4568 [JLOI2011] 飞行路线
tips
- 下面的写法拍平版的逻辑更加简单
- 三元组写法的时间和空间都更加好
- 拍平版的差别是在\(O(n\cdot k)\)的建图
将图拍平后完成操作版本
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 3e5+10;
int dis[N];
bool vis[N];
int n,m,k,s,t;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
// int k,s,t;
cin>>n >> m >> k >> s >> t;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v, w});
e[v].push_back({u, w});
for(int j= 1;j <= k; j ++)
{
e[u + j * n].push_back({v+ j * n , w});
e[v + j * n].push_back({u + j * n , w});
e[u + (j - 1) * n].push_back({v + j * n , 0});
e[v + (j - 1) * n].push_back({u + j * n , 0});
}
}
dijkstra(s);
int ans = INT_MAX;
for(int i = 0 ; i<= k ; i++)
{
ans = min(ans,dis[t + i * n]);
}cout<<ans;
return 0;
}
三元组完成操作
#include<bits/stdc++.h>
using namespace std;
typedef tuple<int,int,int> pii;
const int N = 10010;
struct node{
int v,w;
};
vector<node> e[N];
int n,m,k,dis[N][15],s,t;
bool vis[N];
void dijkstra(int s){
priority_queue<pii,vector<pii> , greater<pii>> q;
memset(dis,0x3f,sizeof(dis));
dis[s][0] = 0;
q.push(pii(0,s,0));
while(q.size()){
auto t = q.top();
q.pop();
int cost = get<0>(t),u = get<1>(t),cnt = get<2>(t);
if(cost > dis[u][cnt]) continue;
for(auto ed : e[u]){
int v =ed.v,w= ed.w;
if(dis[v][cnt] > cost + w){
dis[v][cnt] = cost +w;
q.push(pii(dis[v][cnt],v,cnt));
}if(cnt < k){
if(dis[v][cnt+1] > cost){
dis[v][cnt+1] = cost;
q.push(pii(dis[v][cnt+1],v,cnt+1));
}
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m>>k>>s>>t;
while(m--){
int a,b,c;
cin>>a>>b>>c;
e[a].push_back({b,c});
e[b].push_back({a,c});
}dijkstra(s);
int ans = INT_MAX;
for(int i = 0;i<=k;i++){
ans = min(ans,dis[t][i]);
}cout<<ans;
return 0;
}
T770635 双K最短路
拍平图
Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N = 9e5+10;
int dis[N];
bool vis[N];
int n,m,k,s,t;
vector<pii> e[N];
priority_queue<pii, vector<pii > , greater<pii > > q;
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]= 0;
q.push({0,s});
while(q.size())
{
auto t = q.top();q.pop();
int u = t.second;
if(vis[u]) continue;
vis[u] = 1;
for(auto ed : e[u])
{
int v = ed.first,w = ed.second;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v],v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
// int k,s,t;
cin>>n >> m >> k;
for(int i = 1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
--u,--v;
int wk = w % k;
for(int step = 0 ; step < k ;step++)
{
for(int remain = 0; remain < k ; remain++)
{
int tmpu = u * k * k + step * k + remain;
int tmpv = v * k * k + ((step + 1) % k) * k +((remain + wk) % k);
e[tmpu].push_back({tmpv,w});
tmpv = v * k * k + step * k + remain;
tmpu = u * k * k +((step + 1) % k) * k + ((remain + wk) % k);
e[tmpv].push_back({tmpu,w});
}
}
}
dijkstra(0);
cout<<(dis[(n - 1) * k * k] < 0x3f3f3f3f3f3f3f3f ? dis[( n -1) * k * k] : -1);
return 0;
}
P3831 [SHOI2012] 回家的路
起点和终点的换乘设为0,以便于不明确走纵或横的零代价转移

浙公网安备 33010602011771号