UOJ389【UNR #3】白鸽【计算几何,网络流】

给定 (n) 个点 (m) 条边的无自环的无向图,每个点有坐标 ((x_i,y_i)),求经过 (1) 的欧拉回路关于原点卷绕数的最大值,需判断无解。

(n,mle 2cdot 10^4)(|x_i|,|y_i|le 10^9)


先判断是否有解,然后题目即为给边定向使得每个点的出度 (=) 入度,这是(上下界)网络流模型。

简单的想法是将费用设为极角之差,但因为费用流复杂度跟费用有关所以可能爆炸。

考虑射线法,只有当一条边越过射线时才记 (pm 1) 权值,就可以了。

容量和费用都比较小的时候多路增广会快一些,实现方法就是把 dinic(不用当前弧优化)搬过来,并在 dfs 的时候把流干的点剪枝掉。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 20003, M = N<<2, INF = 0x3f3f3f3f;
template<typename T>
void rd(T &x){
	int ch = getchar(); x = 0; bool f = false;
	for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
	if(f) x = -x;
}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int n, m, x[N], y[N], fa[N], ans, head[N], deg[N], to[M], nxt[M], cap[M], cst[M];
bool vis[N];
void add(int a, int b, int c, int d){
	static int cnt = 1;
	to[++cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; cap[cnt] = c; cst[cnt] = d;
	to[++cnt] = a; nxt[cnt] = head[b]; head[b] = cnt; cap[cnt] = 0; cst[cnt] = -d;
}
int getf(int x){return x == fa[x] ? x : fa[x] = getf(fa[x]);}
void AMOD(int &x){++ x; if(x == N) x = 0;}
void DMOD(int &x){if(!x) x = N; -- x;} 
int S, T, dis[N], Q[N], fr, re;
bool spfa(){
	memset(dis, 0x3f, sizeof dis);
	re = 1; dis[Q[fr = 0] = S] = 0;
	while(fr != re){
		int u = Q[fr]; AMOD(fr); vis[u] = false;
		for(int i = head[u];i;i = nxt[i])
			if(cap[i] && chmin(dis[to[i]], dis[u] + cst[i]) && !vis[to[i]]){
				vis[to[i]] = true;
				if(dis[to[i]] <= dis[Q[fr]]){DMOD(fr); Q[fr] = to[i];}
				else {Q[re] = to[i]; AMOD(re);}
			}
	} return dis[T] < INF;
}
int dfs(int x, int lim){
	if(!lim || x == T) return lim;
	int flow = 0, f; vis[x] = true;
	for(int i = head[x];i && lim;i = nxt[i])
		if(cap[i] && !vis[to[i]] && dis[to[i]] == dis[x] + cst[i] && (f = dfs(to[i], min(lim, cap[i])))){
			flow += f; lim -= f; cap[i] -= f; cap[i^1] += f;
		}
	vis[x] = false; if(!flow) dis[x] = INF; return flow;
}
int main(){
	rd(n); rd(m); S = 0; T = n+1;
	for(int i = 1;i <= n;++ i){
		rd(x[i]); rd(y[i]); fa[i] = i;
	}
	for(int i = 1, u, v;i <= m;++ i){
		rd(u); rd(v);
		vis[u] = vis[v] = true;
		fa[getf(u)] = getf(v);
		if((LL)x[u] * y[v] > (LL)x[v] * y[u]) swap(u, v);
		if(y[u] >= 0 && y[v] < 0){++ans; add(u, v, 1, 2);}
		else add(u, v, 1, 0);
		--deg[u]; ++deg[v];
	}
	for(int i = 1;i <= n;++ i)
		if(vis[i] && getf(i) != getf(1) || deg[i] & 1){
			puts("-1"); return 0;
		}
	for(int i = 1;i <= n;++ i)
		if(deg[i] < 0) add(S, i, -deg[i]>>1, 0);
		else add(i, T, deg[i]>>1, 0);
	memset(vis, 0, sizeof vis);
	while(spfa()) ans -= dis[T] * dfs(S, INF);
	printf("%d
", ans);
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/14930082.html