洛谷 P1401 城市

寫在前面

今天來水主題庫裏的有水分的紫題,隨便一翻居然找到寶了。c++

小清新二分 + 網絡流。git

算法思路

考慮到題目中限制的是最大邊權,要求最大邊權最小,那麼很容易想到二分答案。算法

單調性的證實:最大邊權是對可行的邊的一個限制,所以這個值越大,對可行的邊的限制放的就越寬,可供選擇的邊就不會變少。湊齊 \(t\) 條邊的機會不會變小。知足單調性。數組

考慮到要找到 \(t\) 條可行路徑,能夠抽象成爲在全部邊權的容量都爲 \(1\) 的狀況下,最大流不小於 \(t\)網絡

求解最大流這裏我使用的 dinic 算法。優化

dinic 算法的時間複雜度爲 \(\mathcal O(n^2m)\),實際上遠遠跑不滿,並且它有各類雖然不影響漸進時間複雜度,可是可以大大提升實際運行效率的優化和剪枝。所以實際運行效率極高。spa

Tips

  • 注意存雙向邊、數組越界和每次清空。

Code

#include <bits/stdc++.h>

namespace Basic {
	template <typename Temp> inline void read(Temp & res) {
		Temp fh = 1; res = 0; char ch = getchar();
		for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
		for(; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ '0');
		res = res * fh;
	}
}

using namespace Basic;
using namespace std;

const int Maxn = 2e2 + 5;
const int Maxm = 8e4 + 5;

int n, m, t, x, y, z;
int l = 0, r = 0x7fffffff, mid, ans;

struct e {
	int to, nxt, f;
} b[Maxm];
int head[Maxn], ecnt;
inline void add(int u, int v, int fl) {b[++ecnt] = (e) {v, head[u], fl}; head[u] = ecnt;}

struct edg {
	int v_1, v_2, length;
} b0[Maxm];

queue<int> q;
int dep[Maxn], cur[Maxn];
bool bfs() {
	memset(dep, 0, sizeof(dep));
	while(!q.empty()) q.pop();
	q.push(1); dep[1] = 1;
	while(!q.empty()) {
		int tnow = q.front(); q.pop();
		for(register int i = head[tnow]; i; i = b[i].nxt) {
			int tto = b[i].to, tf = b[i].f;
			if((dep[tto]) || (!tf)) continue;
			dep[tto] = dep[tnow] + 1;
			q.push(tto);
			if(tto == n) return true;
		}
	}
	return false;
}

int dfs(int t, int flow) {
	if(t == n) return flow;
	int rest = flow;
	for(; cur[t] && rest; cur[t] = b[cur[t]].nxt) {
		int tto = b[cur[t]].to, tf = b[cur[t]].f;
		if((dep[tto] != dep[t] + 1) || (!tf)) continue;
		int res = dfs(tto, min(tf, rest));
		rest -= res; b[cur[t]].f -= res; b[cur[t] ^ 1].f += res;
		if(!res) dep[tto] = 0;
		if(!rest) return flow;
	}
	return flow - rest;
}

bool check(int lim) {
	int Maxflow = 0;
	memset(head, 0, sizeof(head)); ecnt = 1;
	for(register int i = 1; i <= m; ++i) {
		if(b0[i].length <= lim) {
			add(b0[i].v_1, b0[i].v_2, 1);
			add(b0[i].v_2, b0[i].v_1, 1);
		}
	}
	while(bfs()) {
		memcpy(cur, head, sizeof(cur));
		Maxflow += dfs(1, 0x7fffffff >> 1);
	}
	return Maxflow >= t;
}

int main() {
	read(n); read(m); read(t);
	for(register int i = 1; i <= m; ++i) {read(b0[i].v_1); read(b0[i].v_2); read(b0[i].length);}
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(check(mid)) ans = mid, r = mid - 1;
		else l = mid + 1; 
	}
	printf("%d", ans);
	return 0;
}
相關文章
相關標籤/搜索