Wannafly挑战赛2 B-Travel(抽40个点跑最短路)

发现这道题真的挺难写的。。。如果单纯是个环,我们直接用前缀和就能求出两点之间的距离,现在额外添加了一些边。我们分情况讨论。

1.只走环上的点,那么直接前缀和相减就能得到答案。

2.走了传送门。从起点出发,那么可能先走a传送门,再走b传送门……最终到达终点。

我们最后只需要在1得到的答案和2得到的答案中取min即可。

1.很好解决,先处理出前缀和 和所有边的总和length,然后两个点的前缀和相减取绝对值可以得到某个方向的距离ans,再用length-ans可以得到另外一个方向的距离。取min。

2.我们可以发现这种走法可以理解为从任意一个传送门开始走,到达某个点,其中起点s到终点e就是该传送门到起点s的距离+该传送门到终点e的距离,所以我们跑最短路然后得到一个最短路的网络,我们此时得到了该传送门到其他任何一个点的距离。我们只需要把传送门所在的点都跑一遍最短路,最多也才40个点,就可以得到整个网络两点之间的距离了。然后读入起点s和终点e后,我们直接暴力这40个点,取min(p点到s的距离+p点到e的距离)即可。

代码如下:

#include
using namespace std;
#define SIZE(x) (int)(x).size()
typedef long long LL;
typedef pair pii;

const int maxn = 60000 + 5;
const LL INF = 1e18;

int n, m;
LL G[45][maxn], sum[maxn], a[maxn], length;
vector  edge[maxn];
vector  ver;

void dijkstra(int s) {
	priority_queue , greater > q;
	for(int i = 1; i <= n; i++)
		G[s][i] = INF;
	G[s][ver[s]] = 0;
	q.push(pii(G[s][ver[s]], ver[s]));
	while(!q.empty()) {
		pii tmp = q.top();
		q.pop();
		if(G[s][tmp.second] < tmp.first)
			continue;
		int u = tmp.second;
		for(int i = 0; i < SIZE(edge[u]); i++) {
			int v = edge[u][i].second;
			LL val = edge[u][i].first;
			if(G[s][v] > G[s][u] + val) {
				G[s][v] = G[s][u] + val;
				q.push(pii(G[s][v], v));
			}
		}
	}
}

int main() {
#ifndef ONLINE_JUDGE
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
#endif
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		length += a[i];
		sum[i] = a[i] + sum[i - 1];
		edge[i].push_back(pii(a[i], (i % n) + 1));
		edge[(i % n) + 1].push_back(pii(a[i], i));
	}
	while(m--) {
		int u, v, val;
		cin >> u >> v >> val;
		edge[u].push_back(pii(val, v));
		edge[v].push_back(pii(val, u));
		ver.push_back(u);
		ver.push_back(v);
	}
	int p = unique(ver.begin(), ver.end()) - ver.begin();
	for(int i = 0; i < p; i++) {
		dijkstra(i);
	}
	int k;
	cin >> k;
	while(k--) {
		int u, v;
		cin >> u >> v;
		LL ans = abs(sum[v - 1] - sum[u - 1]);
		ans = min(ans, length - ans);
		for(int i = 0; i < p; i++) {
			ans = min(ans, G[i][u] + G[i][v]);
		}
		cout << ans << endl;
	}
	return 0;
}


你可能感兴趣的:(Dijkstra(点对点))