给定 (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);
}