2095: [Poi2010]Bridges

混合图的欧拉回路一般解法:
二分 + 最大流
先二分,然后判断该图是否能构成欧拉回路
考虑欧拉回路的成立条件,入度等于出度
也就是说,对于有向边,只用考虑其对入度出度的贡献,
然后对于无向边就要考虑其方向…
那么先任意规定无向边的方向,然后跑最大流。
在满足没有点出入度为0或出入度差为奇数(因为此时改变无向边的方向出入度之差变化为2)的前提下
如果能满流,那么就成立,否则不成立
考虑为何这样是对的。。。
实际上一开始无向边规定的那一个流量1,相当于跑了以后出入度变化量为2,
所以s ->i的流量为(out-in)/2,i ->t的流量为(in-out)/2
所以跑最大流的过程实际上是把边的方向重新改变.
c++代码如下:

#include
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x ; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}

const int N = 1e3+50,M = 4e5+500,inf = 1e9+7;
struct Str { int u,v,c,d; }edge[M];
int cur[N],head[N],nxt[M],to[M],f[M],tot;
int n,m,s,t,ans,d[N],in[N],out[N];

inline void add(int x,int y,int w)
{
    f[tot] = w;
    to[tot] = y;
    nxt[tot] = head[x];
    head[x] = tot ++;
}

inline bool bfs()
{
    queue<int>q ;
    memset(d,0,sizeof d);
    q.push(s); d[s] = 1;
    while(!q.empty())
    {
        int x = q.front();q.pop();cur[x] = head[x];
        for(register int i = head[x];~i;i = nxt[i])
            if(!d[to[i]] && f[i])
            {
                d[to[i]] = d[x] + 1;
                q.push(to[i]);
            }
    }
    return d[t];
}

int dfs(int x,int w)
{
    if(x == t || !w) return w;
    int F,flow = 0;
    for(register int&i=cur[x];~i;i=nxt[i])
        if(d[to[i]] == d[x] + 1 && ( F = dfs(to[i],min(f[i],w))))
        {
            f[i] -= F;f[i^1] += F;
            w -= F; flow += F;
            if(!w) break;
        }
    return flow;    
}

inline bool check(int x)
{
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
    memset(head,-1,sizeof head);
    tot = 0;
    rep(i,1,m)
    {
        if(edge[i].c <= x){
            out[edge[i].v]++; in[edge[i].u]++;
        }else return false;
        if(edge[i].d <= x)
        {
            add(edge[i].v,edge[i].u,1);
            add(edge[i].u,edge[i].v,0);
        }
    }

    int sum = 0,ans = 0;
    rep(i,1,n)
        if((abs(in[i] - out[i]) & 1) || (!in[i] && !out[i]))
            return false;
        else if(out[i] - in[i] > 0)
        {
            add(s,i,(out[i] - in[i]) / 2);
            add(i,s,0);
            sum += (out[i] - in[i]) / 2;
        }else if(in[i] - out[i] > 0)
        {
            add(i,t,(in[i] - out[i]) / 2);
            add(t,i,0);
        }

    while(bfs())
        ans += dfs(s,inf);

    return ans == sum;
}

int main()
{
    read(n); read(m);
    rep(i,1,m)
    {
        read(edge[i].u); read(edge[i].v);
        read(edge[i].c); read(edge[i].d);
        if(edge[i].c > edge[i].d)
            swap(edge[i].c,edge[i].d),
            swap(edge[i].u,edge[i].v);
    }

    s = 0;t = n + 1;
    int l = 1,r = 1e4+50,mid; 
    while(l <= r)
    {
        if(check(mid = l + r >> 1)) ans = mid,r = mid - 1;
        else l = mid + 1;
    }

    if(ans ) cout << ans << '\n';
    else puts("NIE");

    return 0;
}

你可能感兴趣的:(BZOJ,BZOJ刷题录)