区队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

  1. 下面的写法拍平版的逻辑更加简单
  2. 三元组写法的时间和空间都更加好
  3. 拍平版的差别是在\(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,以便于不明确走纵或横的零代价转移

posted @ 2026-09-08 13:19  Zhenggeek  阅读(3)  评论(0)    收藏  举报