bzoj2095 Bridges

Bridges

题目背景:

bzoj2095

分析:今天get到一种新技能,混合图欧拉回路,首先我们来考虑下普通的有向图,当且仅当每一个点的入度等于出度时,存在一个欧拉回路,无向图则是每一个点的度数为偶数,现在我们考虑混合图,首先对于有向边直接选择,对于无向边,我们随便定向,之后如果原图存在欧拉回路,那么每一个点的入度和出度之差一定是偶数(若有一条边方向相反,则会有两个点的入度和出度之差的绝对值加2),考虑调整的方式,我们选择网络流,对于每一个入度大于出度的点,从源点向当前点连接边权为(入度  出度)/ 2的边,对于每一个出度大于入度的点,从当前点向汇点连边权为(出度  入度)/ 2的边,对于每一条我们定过向的无向边,反向连一条边权为1的边,表示经过一次这条边就表示将这条有向边反向,调整2的入度和出度。然后直接二分能够承受的风力大小,建图跑最大流,判断获得的最大流是否为之前连向起点的权值和,若满足则存在否则不存在。注意原图可能不连通,所以我还搞了个并查集,事实上应该不用······

Source

/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
  
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
  
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
  
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
    if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
    *oh++ = c;
}
  
template<class T>
inline void W(T x) {
    static int buf[30], cnt;
    if (x == 0) write_char('0');
    else {
        if (x < 0) write_char('-'), x = -x;
        for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
        while (cnt) write_char(buf[cnt--]);
    }
}
  
inline void flush() {
    fwrite(obuf, 1, oh - obuf, stdout);
}
  
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
  
const int MAXN = 1000 + 10;
const int INF = ~0u >> 1;
  
struct node {
    int to, w, f, rev;
    node(int to = 0, int w = 0, int rev = 0) : to(to), w(w), f(0), rev(rev) {}
} ;
  
struct edge {
    int a, b, c, d;
    edge(int a = 0, int b = 0, int c = 0, int d = 0) : a(a), b(b), c(c), d(d) {}
} edges[MAXN << 1];
  
std::vector<node> edge[MAXN];
  
int n, m, a, b, c, d, s, t;
int dis[MAXN], temp[MAXN], gap[MAXN], father[MAXN];
int out_degree[MAXN], in_degree[MAXN];
  
inline void add_edge(int x, int y, int w) {
    edge[x].push_back(node(y, w, edge[y].size()));
    edge[y].push_back(node(x, 0, edge[x].size() - 1));
}
  
inline void read_in() {
    R(n), R(m), s = 0, t = n + 1;
    for (int i = 1; i <= m; ++i)
        R(edges[i].a), R(edges[i].b), R(edges[i].c), R(edges[i].d);     
}

inline int sap(int cur, int flow, int s, int t, int n) {
    if (cur == t) return flow;
    int del = 0;
    static int temp[MAXN];
    for (int p = temp[cur]; p < edge[cur].size(); ++p) {
        node *e = &edge[cur][p];
        if (e->w > 0 && dis[e->to] + 1 == dis[cur]) {
            int ret = sap(e->to, std::min(e->w, flow - del), s, t, n);
            e->w -= ret, edge[e->to][e->rev].w += ret, temp[cur] = p;
            if ((del += ret) == flow || dis[cur] >= n) 
                return temp[cur] = 0, del;
        }
    }
    if (--gap[dis[cur]] == 0) dis[s] = n;
    gap[++dis[cur]]++, temp[cur] = 0;
    return del;
}
 
inline int sap(int s, int t, int n) {
    int ret = 0;
    memset(gap, 0, sizeof(int) * (n + 1));
    memset(dis, 0, sizeof(int) * (n + 1));
    for (gap[0] = n; dis[s] < n; ) ret += sap(s, ~0u >> 1, s, t, n);
    return ret;
}
 
inline int get_father(int x) {
    return (father[x] == x) ? x : (father[x] = get_father(father[x]));
}
  
inline void unite(int x, int y) {
    int fa1 = get_father(x), fa2 = get_father(y);
    if (fa1 != fa2) father[fa1] = fa2;
}
  
inline bool check(int mid) {
    for (int i = 0; i <= n + 1; ++i) 
        edge[i].clear(), father[i] = i, in_degree[i] = 0, out_degree[i] = 0;
    for (int i = 1; i <= m; ++i) {
        int u = edges[i].a, v = edges[i].b;
        if (edges[i].c <= mid && edges[i].d <= mid)
            out_degree[u]++, in_degree[v]++, add_edge(v, u, 1), unite(u, v);
        else if (edges[i].c <= mid) 
            out_degree[u]++, in_degree[v]++, unite(u, v);
        else if (edges[i].d <= mid) 
            out_degree[v]++, in_degree[u]++, unite(u, v);
    }
      
    int ans = 0, fa = get_father(1), tt = 0;
    for (int i = 1; i <= n; ++i) {
        if (get_father(i) != fa) return false;
        int x = in_degree[i] - out_degree[i];
        if (abs(x) & 1) return false;
        if (x > 0) add_edge(s, i, x / 2), ans += x / 2;
        else if (x < 0) add_edge(i, t, -x / 2), tt -= x / 2; 
    } 
    return (sap(s, t, t + 1) == ans);
}
  
inline void binary() {
    int l = -1, r = 1000 + 1;
    while (l + 1 < r) {
        int mid = l + r >> 1;
        check(mid) ? (r = mid) : (l = mid);
    }
    if (r == 1000 + 1) std::cout << "NIE";
    else std::cout << r;
}
  
int main() {
//  freopen("data.in", "r", stdin);
//  freopen("data.out", "w", stdout);
    read_in();
    binary();
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值