题解Red-Blue Graph Codeforces 1288F 上下界费用流

Posted mlystdcall

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Red-Blue Graph Codeforces 1288F 上下界费用流相关的知识,希望对你有一定的参考价值。

特别有趣的一个题。

很容易想到可能是网络流问题,关键在于如何刻画诸如“Red边比Blue边多”这样的限制。

最后我还是看了题解。。。很有趣的思路。

对于每条边,假设她连接了左边点u和右边点v,那么:

  • 从u到v连一条容量是1,费用是r的边,如果走了这条边,意味着这条边染Red。

  • 从v到u连一条容量是1,费用是b的边,如果走了这条边,意味着这条边染Blue。

对于左边的有Red限制的点,显然要求这个点“出去的流量”大于“进来的流量”,因此从这个点连向T,下界是1,上界是INF,费用是0。

其他情况可以比葫芦画瓢推出如何连边,太简单了不写了。

所以是一个上下界的最小费用可行流。

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> pii;
const int N = 210;
int _w;

namespace MCMF {
    const int MAXN = 1000010;
    const int MAXM = 1000010;
    
    struct Edge {
        int u, v, c, f, w;
        Edge() {}
        Edge( int uu, int vv, int cc, int ff, int ww ) {
            u = uu, v = vv, c = cc, f = ff, w = ww;
        }
    };
    
    int n, m, s, t;
    int head[MAXN], nxt[MAXM];
    Edge edge[MAXM];
    
    void init( int nn ) {
        n = nn, m = 0;
        for( int i = 0; i < n; ++i )
            head[i] = -1;
    }
    int adde( int u, int v, int c, int w ) {
        int e = m;
        edge[m] = Edge(u, v, c, 0, w);
        nxt[m] = head[u], head[u] = m++;
        edge[m] = Edge(v, u, 0, 0, -w);
        nxt[m] = head[v], head[v] = m++;
        return e;
    }
    
    int res[MAXN], from[MAXN];
    int dis[MAXN];
    bool inq[MAXN];
    queue<int> q;
    
    bool spfa() {
        for( int i = 0; i < n; ++i )
            dis[i] = 1e9;
        dis[s] = 0, inq[s] = 1, q.push(s), res[s] = 1e9;
        while( !q.empty() ) {
            int u = q.front(); q.pop();
            inq[u] = 0;
            for( int i = head[u]; ~i; i = nxt[i] ) {
                Edge &e = edge[i];
                if( e.c > e.f && dis[u] + e.w < dis[e.v] ) {
                    dis[e.v] = dis[u] + e.w;
                    res[e.v] = min( res[u], e.c-e.f );
                    from[e.v] = i;
                    if( !inq[e.v] )
                        inq[e.v] = 1, q.push(e.v);
                }
            }
        }
        return dis[t] != 1e9;
    }
    void augment() {
        int u = t, f = res[t];
        while( u != s ) {
            int i = from[u];
            edge[i].f += f;
            edge[i^1].f -= f;
            u = edge[i].u;
        }
    }
    pii solve( int ss, int tt ) {
        s = ss, t = tt;
        int flow = 0;
        int cost = 0;
        while( spfa() ) {
            flow += res[t];
            cost += res[t] * dis[t];
            augment();
        }
        return pii(flow, cost);
    }
}

int n1, n2, m, r, b;
char Lcolor[N], Rcolor[N], Ecolor[N];
pii edge[N];
int ans;

int S, T, SS, TT, nid, Lid[N], Rid[N];
int eid_red[N], eid_blue[N];

int add_edge( int u, int v, int l, int r, int w ) {
    int e = MCMF::adde(u, v, r-l, w);
    if( l ) {
        MCMF::adde(SS, v, l, 0);
        MCMF::adde(u, TT, l, 0);
    }
    return e;
}

bool solve() {
    S = nid++, T = nid++, SS = nid++, TT = nid++;
    for( int i = 1; i <= n1; ++i )
        Lid[i] = nid++;
    for( int i = 1; i <= n2; ++i )
        Rid[i] = nid++;
    MCMF::init(nid);
    add_edge(T, S, 0, 1e9, 0);
    int low_sum = 0;
    for( int i = 1; i <= n1; ++i )
        if( Lcolor[i] == 'R' ) {
            add_edge(S, Lid[i], 1, 1e9, 0);
            ++low_sum;
        } else if( Lcolor[i] == 'B' ) {
            add_edge(Lid[i], T, 1, 1e9, 0);
            ++low_sum;
        } else {
            add_edge(S, Lid[i], 0, 1e9, 0);
            add_edge(Lid[i], T, 0, 1e9, 0);
        }
    for( int i = 1; i <= n2; ++i )
        if( Rcolor[i] == 'R' ) {
            add_edge(Rid[i], T, 1, 1e9, 0);
            ++low_sum;
        } else if( Rcolor[i] == 'B' ) {
            add_edge(S, Rid[i], 1, 1e9, 0);
            ++low_sum;
        } else {
            add_edge(S, Rid[i], 0, 1e9, 0);
            add_edge(Rid[i], T, 0, 1e9, 0);
        }
    for( int i = 1; i <= m; ++i ) {
        int L = edge[i].first;
        int R = edge[i].second;
        eid_red[i] = add_edge(Lid[L], Rid[R], 0, 1, r);
        eid_blue[i] = add_edge(Rid[R], Lid[L], 0, 1, b);
    }
    pii tmp = MCMF::solve(SS, TT);
    if( tmp.first != low_sum ) return false;
    ans = tmp.second;
    for( int i = 1; i <= m; ++i ) {
        using MCMF::edge;
        int R = eid_red[i];
        int B = eid_blue[i];
        if( edge[R].f && !edge[B].f ) {
            Ecolor[i] = 'R';
        } else if( !edge[R].f && edge[B].f ) {
            Ecolor[i] = 'B';
        } else {
            Ecolor[i] = 'U';
        }
    }
    return true;
}

int main() {
    _w = scanf( "%d%d%d%d%d", &n1, &n2, &m, &r, &b );
    _w = scanf( "%s", Lcolor+1 );
    _w = scanf( "%s", Rcolor+1 );
    for( int i = 1; i <= m; ++i ) {
        _w = scanf( "%d%d", &edge[i].first, &edge[i].second );
    }
    if( solve() ) {
        printf( "%d
", ans );
        Ecolor[m+1] = 0;
        puts(Ecolor + 1);
    } else {
        puts("-1");
    }
    return 0;
}

以上是关于题解Red-Blue Graph Codeforces 1288F 上下界费用流的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces1606 D. Red-Blue Matrix(思维,排序)

CF662B Graph Coloring题解--zhengjun

[LeetCode]题解(python):133-Clone Graph

POJ 1737 Connected Graph 题解(未完成)

LeetCode题解之Clone Graph

题解HDU5824 graph