其他分享
首页 > 其他分享> > 【UOJ#389】【UNR#3】白鸽(欧拉回路,费用流)

【UOJ#389】【UNR#3】白鸽(欧拉回路,费用流)

作者:互联网

uoj传送门

题意:
二维平面上给出一些点,同时给出一些无向边连接两个点。
现在从\(1\)号点出发,经过每条边一次,最终回到\(1\)号点。问最终绕原点顺时针旋转最多多少圈。

思路:

至于为什么最后需要得到最大流才行,因为我们一定需要将所规定数量的边进行反向,这时我们同时还要得到最小代价,所以就是最大流最小费用了。
这跟这道题很像,就是多了个费用。
注意一下,可能有一些孤立的点存在,这时也可能存在欧拉回路。

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
//#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;

int n, m;
int x[N], y[N];

int head[N],vis[N],d[N],a[N],pa[N],pre[N];
struct Edge{
    int v,next,c,w;
}e[N];
int tot ;
void adde(int u,int v,int c,int w){
    e[tot].v=v;e[tot].next=head[u];e[tot].w=w;e[tot].c=c;head[u]=tot++;
    e[tot].v=u;e[tot].next=head[v];e[tot].w=-w;e[tot].c=0;head[v]=tot++;
}
int spfa(int s,int t,int &flow,int &cost){
    for(int i=0;i<=t;i++) d[i]=a[i]=INF;d[s]=0;
    memset(vis,0,sizeof(vis));vis[s]=1;
    memset(pre,-1,sizeof(pre));memset(pa,-1,sizeof(pa));
    queue <int> q;q.push(s);
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(e[i].c>0 && d[v]>d[u]+e[i].w){
                d[v]=d[u]+e[i].w;
                pa[v]=u;pre[v]=i;
                a[v]=min(a[u],e[i].c);
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(d[t]==INF) return 0;
    flow+=a[t];
    cost+=a[t]*d[t];
    for(int i=t;i!=-1;i=pa[i]){
        int edge = pre[i];
        e[edge].c-=a[t];
        e[edge^1].c+=a[t];
    }
    return 1;
}
int Min_cost(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost));
    return cost;
}

int f[N];
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);}
void Union(int x, int y) {
    int fx = find(x), fy = find(y);
    if(fx != fy) f[fx] = fy;
}
int deg[N];
void run() {
    for(int i = 1; i <= n; i++) {
        cin >> x[i] >> y[i];
    }
    memset(head, -1, sizeof(head));
    int ans = 0;
    for(int i = 1; i <= n; i++) f[i] = i;
    for(int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        if(1ll * x[u] * y[v] > 1ll * x[v] * y[u]) swap(u, v);
        //u -> v
        ++deg[u], --deg[v];
        Union(u, v);
        int val = (y[u] > 0 && y[v] <= 0);
        adde(u, v, 1, 2 * val);
        ans += val;
        vis[u] = vis[v] = true;
    }
    for(int i = 1; i <= n; i++) {
        if(vis[i] && find(i) != find(1)) {
            cout << -1 << '\n';
            return;
        }
    }
    for(int i = 1; i <= n; i++) {
        if(deg[i] & 1) {
            cout << -1 << '\n';
            return;
        }
    }
    int S = 0, T = n + 1;
    for(int i = 1; i <= n; i++) {
        if(deg[i] > 0) {
            adde(S, i, deg[i] / 2, 0);
        } else if(deg[i] < 0) {
            adde(i, T, -deg[i] / 2, 0);
        }
    }
    ans -= Min_cost(S, T);
    cout << ans << '\n';
}

int main() {
//    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
#ifdef Local
    freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
    while(cin >> n >> m) run();
    return 0;
}

标签:UNR,int,void,head,tot,cost,389,UOJ,define
来源: https://www.cnblogs.com/heyuhhh/p/11735142.html