1. 程式人生 > >Wannafly挑戰賽2 B-Travel(抽40個點跑最短路)

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<bits/stdc++.h>
using namespace std;
#define SIZE(x) (int)(x).size()
typedef long long LL;
typedef pair<LL, int> pii;

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

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

void dijkstra(int s) {
	priority_queue <pii, vector<pii>, greater<pii> > 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;
}