• 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);
    }
    
  • 相关阅读:
    Rebuilding a heap
    Comparison Operators Modified by ANY, SOME, or ALL
    个人外包项目全记 Best Partner
    你需要明白的索引和约束的前缀(AK,PK,IX,CK,FK,DF,UQ)
    This Android SDK requires Android Developer Toolkit version 17.0.0 or above!!(SDk版本一致)解决办法:
    web端获取系统当前时间
    This Android SDK requires Android Developer Toolkit version 17.0!!(SDk版本一致)解决办法:
    The configuration may be corrupt or incomplete解决方案
    SSH框架
    sdk下proguard.cfg文件找不到的解决办法
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/14930082.html
Copyright © 2020-2023  润新知