計蒜客習題-道路阻攔 求最小割的邊數

UPD:原來是因爲參數傳遞是用棧控制的 按照如下方式傳參會變成addedge(d,c,v,u)addedge(d,c,v,u) 就……可以防hack?


快讀玄學錯誤浪費我一個晚上+早上
發現如果不直接在addedge()函數裏用read做參數 比如addedge(read(),read(),read(),read())addedge(read(),read(),read(),read())
而是先聲明u,v,c,d 用read()讀入的值存在裏面
然後addedge(u,v,c,d)addedge(u,v,c,d)
就……就tmA了
而且按照第一種寫法 在ins函數裏輸出c 結果會輸出v的值……所有邊都是這樣 直接導致wa……


題解:
如果題目最大邊數是E(雙向邊就2E)
割斷每條邊的代價就是邊的容量 求代價最小時割的最小邊數
我們可以在插邊的時候 把邊的容量設成(E+1)cap+1(E+1)*cap+1 其中capcap是邊原來的容量
這樣的話 dinic()算出來的最小割結果記爲ans 原題求解的最小代價即爲ans/(E+1)()ans/(E+1)(向下取整)
因爲所有弧的流量乘的那個(E+1)(E+1)都被除掉了 剩下的所有多加的1的和是小於EE(最大邊數)

同理 求的最小代價下的最小割邊數 可以用ans mod (E+1)ans \ mod \ (E+1)表示 因爲所有多加的1代表了邊數 多乘的(E+1)被模掉不影響結果

求代價最小的最小割邊數代碼如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int n, m;
const int maxn = 1007;
const ll E = 200001;
const ll inf = 100000000000;
struct edge {
	int v, next;
	ll c;
}e[E << 1];
int p[maxn], eid = 0, d[maxn];
int S, T;
void init() {
	memset(p, -1, sizeof(p));
	eid = 0;
}
void ins(int u, int v, ll c) {
	e[eid].c = c*E+1; e[eid].v = v; e[eid].next = p[u];  p[u] = eid++;
	e[eid].c = 0; e[eid].v = u; e[eid].next = p[v]; p[v] = eid++;
}
void addedge(int u, int v, ll c, int d) {
	if (d == 1) {
		ins(u, v, c);
		ins(v, u, c);
	}
	else {
		ins(u, v, c);
	}
}
bool bfs() {
	memset(d, -1, sizeof(d));
	int v;
	queue<int> q;
	q.push(S);
	d[S] = 0;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = p[u]; ~i; i = e[i].next) {
			v = e[i].v;
			//printf("%lld\n", e[i].c);
			if (e[i].c && d[v] == -1) {
				d[v] = d[u] + 1;
				q.push(v);
				if (v == T) return true;
			}
		}
	}
	return false;
}
ll dfs(int u, ll flow) {
	if (u == T) return flow;
	ll res = 0;
	int v;
	for (int i = p[u]; ~i; i = e[i].next) {
		v = e[i].v;
		//printf("%d %lld\n", v, e[i].c);
		if (e[i].c  && d[v] == d[u] + 1){
			ll tmp = dfs(v, min(flow, e[i].c));
			//printf("%lld\n", tmp);
			res += tmp;
			flow -= tmp;
			e[i].c -= tmp;
			e[i ^ 1].c += tmp;
			if (flow == 0) break;
		}
	}
	if (res == 0) d[u] = -1;
	//printf("%lld\n", res);
	return res;
}
ll dinic() {
	ll res = 0;
	while (bfs()) res += dfs(S, inf);
	return res;
}
inline int read() {
	int s = 0, f = 1; char c = getchar(); while (c<'0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
	while (c >= '0'&&c <= '9') { s = s * 10 + c - '0'; c = getchar(); }
	return s*f;
}
int main() {
	n = read();
	m = read();
	S = 0;
	T = n - 1;
	init();
	int u, v, c, d;
	while (m--) {
		u = read(); v = read(); c = read(); d = read();
		addedge(u,v,c,d);
	}
	cout << dinic() % E;
	//getchar();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章