51nod算法马拉松29 图

传送门
因为给出的是一个非A即B的问题,我们可以考虑一下最小割(不知道是不是在乱说。。)
然后我们可以定义对于一个点u,如果在切割后u与源点S相连,那么表示u在A集合,否则u与T相连,在B集合。
然后我们对于给出的无向图中已有的边(u,v),S连向u和v,流量为 ∣ u − v ∣ |u-v| uv,表示如果u和v任意一个不在A集合,都将付出 ∣ u − v ∣ |u-v| uv的代价。
然后我们对于给出的无向图中没有的边(u,v),u和v连向T,流量为 ∣ u − v ∣ |u-v| uv,表示如果u和v任意一个不在B集合,都将付出 ∣ u − v ∣ |u-v| uv的代价。
对于任意两个点u,v,给u和v连一条边,流量也是|u-v|,表示,如果u和v不在一个集合里面,将付出 ∣ u − v ∣ |u-v| uv的代价。
考虑任意两个点u,v,都有一个与S或T构成的三角形,所以只要S和u和v任意一个和其他两个不在一个集合,那么就会付出 2 ∣ u − v ∣ 2|u-v| 2uv的代价,就得不到题意中的分数 ∣ u − v ∣ |u-v| uv
所以答案就是 ∑ u , v ∈ { 1 , 2 , . . . , n } ∣ u − v ∣ − M a x f l o w 2 \frac{\sum_{u,v\in \{1,2,...,n\}}|u-v| -Maxflow}{2} 2u,v{1,2,...,n}uvMaxflow

#include 
using namespace std;
const int MAXN = 1e3 + 5;
int n, m, S, T, a[MAXN], vd[MAXN], d[MAXN];
long long ans = 0;
inline void GET(int&n) {
	char c; n = 0; do c = getchar(); while('0' > c || c > '9');
	while('0' <= c && c <= '9') { n = n *10 + c - '0'; c = getchar(); }
}
bool mp[MAXN][MAXN];
int f[MAXN][MAXN];
inline int abs(int x) { return x > 0 ? x : -x; }
int Aug(int u, int augco) {
	if(u == T) return augco;
	int delta = 0, augc = augco, dmin = T-1;
	for(int v = 1; v <= T; ++ v) if(f[u][v] > 0) {
		if(d[v] + 1 == d[u]) {
			delta = Aug(v, min(f[u][v], augc));
			f[u][v] -= delta; f[v][u] += delta;
			augc -= delta;
			if(!augc || d[S] >= T) return augco - augc;
		}
		if(d[v] < dmin) dmin = d[v];
	}
	if(augco == augc) {
		-- vd[d[u]];
		if(!vd[d[u]]) d[S] = T;
		++ vd[d[u] = dmin+1];
	}
	return augco - augc;
}
void sap() {
	vd[0] = T;
	while(d[S] < T)
        ans += Aug(S, 0x3f3f3f3f);
}
int main() {
	cin >> n >> m;
	int u, v;
	for(int i = 1; i <= m; ++ i) {
		GET(u); GET(v);
		mp[u][v] = mp[v][u] = 1;
	}
	S = n + 1; T = S + 1;
	long long delta = 0;
	for(int i = 1; i <= n; ++ i)
		for(int j = i + 1; j <= n; ++ j) {
			if(mp[i][j]) f[S][i] += j-i, f[S][j] += j-i;
			else f[i][T] += j-i, f[j][T] += j-i;
			f[i][j] += j-i; f[j][i] += j-i;
			delta += j-i;
		}
	sap();
	ans /= 2;
	printf("%lld\n", delta - ans);
	return 0;
}

你可能感兴趣的:(网络流)