P3906 Geodetic集合 最短路的点集

 P3906 Geodetic集合 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

把无向边看作长度均为1的有向边然后求最短路即可。但是此题需要把所有最短路上的点放入集合。并随机取两点访问,首先会想到floyd,处理完最短路后枚举顶点。

设起始点终点为 s ,e 和 k如果满足:

gra[s][k]+gra[k][e]=gra[s][e]

则说明k节点在s<->e的最短路上。

同理,我们也可以使用dijkstra ,但是dij是单元最短路,此图为无向边,所以需要起点跑一遍最短路,终点跑一遍最短路。然后同样用上面的条件判断即可得到节点是否在最短路上。

Floyd O(n^3)

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define int ll
#define mm(a) memset(a,0,sizeof(a))
#pragma warning(disable:4996);
const int N = 2e3 + 10;
const int mod = 998244353;
int T, n, m, k, q, t,x;
int arr[N];
vector<int>gra[N];
int g[N][N];
void  floyd() {
	for (int k = 1; k <= n; k++) {
		for (int j = 1; j <= n; j++) {
			for (int i = 1; i <= n; i++) {
				g[j][i] = g[i][j] = min(g[j][i], g[j][k] + g[k][i]);
			}
		}
	}
}
signed main() {
	cin >> n >> m;
	for (int j = 1; j <= n; j++) {//初始化,记得判断i==j
		for (int i = 1; i <= n; i++) {
			if (i == j)continue;
			g[i][j] = g[j][i] = INT_MAX;
		}
	}
	int a, b;
	for (int j = 1; j <= m; j++) {
		
		cin >> a >> b;
		g[a][b] = 1;
		g[b][a] = 1;
	}
	floyd();
	cin >> k;
	while (k--) {
		cin >> a >> b;
		for(int j=1;j<=n;j++)
			if (g[a][j] + g[j][b] == g[a][b]) {
				cout << j << " ";
			}
		cout << endl;
	}
	
}

Dijkstra(n^2log)

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define int ll
#define mm(a) memset(a,0,sizeof(a))
#pragma warning(disable:4996);
const int N = 2e3 + 10;
const int mod = 998244353;
int T, n, m, k, q, t,x;
int arr[N];

struct node {
	int to, pw;
	int operator<(const node& a)const {
		return pw > a.pw;
	}
};
vector<node>gra[N];
int dis1[N], dis2[N];
void dij1(int s) {
	for (int j = 1; j <= n; j++)dis1[j] = INT_MAX;
	int vis[N] = { 0 };
	int now = s;
	dis1[now] = 0;
	priority_queue<node>q;
	q.push({ now,dis1[now] });
	while (!q.empty()) {
		now = q.top().to;
		q.pop();
		if (vis[now])continue;
		vis[now] = 1;
		for ( auto& x : gra[now]) {
			int to = x.to;
			if (!vis[to] && dis1[to] > dis1[now] + x.pw) {
				dis1[to] = dis1[now] + x.pw;
				q.push({ to,dis1[to] });
			}
		}
	}
}
void dij2(int s) {
	for (int j = 1; j <= n; j++)dis2[j] = INT_MAX;
	int vis[N] = { 0 };
	int now = s;
	dis2[now] = 0;
	priority_queue<node>q;
	q.push({ now,dis2[now] });
	while (!q.empty()) {
		now = q.top().to;
		q.pop();
		if (vis[now])continue;
		vis[now] = 1;
		for (auto& x : gra[now]) {
			int to = x.to;
			if (!vis[to] && dis2[to] > dis2[now] + x.pw) {
				dis2[to] = dis2[now] + x.pw;
				q.push({ to,dis2[to] });
			}
		}
	}
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0);
#ifndef ONLINE_JUDGE
	freopen("out.txt", "w", stdout);
#endif // !ONLINE_JUDGE
	cin >> n >> m;
	int a, b;
	for (int j = 1; j <= m; j++) {
		
		cin >> a >> b;
		gra[a].push_back({b,1});
		gra[b].push_back({a,1});
	}
	cin >> k;
	while (k--) {
		cin >> a >> b;
		dij1(a);
		dij2(b);
		for (int j = 1; j <= n; j++) {
			if (dis1[j] + dis2[j] == dis1[b]) {
				cout << j << " ";
			}
			//cout << dis1[j] << " ";
		}
		cout << endl;
	}
	
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值