【题解】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\n", ans );
        Ecolor[m+1] = 0;
        puts(Ecolor + 1);
    } else {
        puts("-1");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/mlystdcall/p/12246941.html

时间: 2024-10-07 12:43:49

【题解】Red-Blue Graph Codeforces 1288F 上下界费用流的相关文章

【bzoj1927】[Sdoi2010]星际竞速 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6832464.html 题目描述 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座α星的悠悠也是其中之一.赛车大赛的赛场由N颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值.大赛要求车手们从一颗与这N颗行星之间没有任何航路的天体出发,访问这N颗行星每颗恰好一次,首先完成这一目标的人获得胜利.由于赛制非常开放,很多人驾驶着千奇百怪的自制赛

【bzoj4108】[Wf2015]Catering 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6832537.html 题目描述 有一家装备出租公司收到了按照时间顺序排列的n个请求. 这家公司有k个搬运工.每个搬运工可以搬着一套装备按时间顺序去满足一些请求.一个搬运工从第i个请求的位置把东西搬到第j个请求的位置需要一些费用.公司的编号是1,请求的编号是2到n+1.所有搬运工必需从公司出发. 求满足所有请求所需的最小搬运费用. 输入 有可能有多组数据.(实际上没有) 第一行两个正整数n,k. 接下来n行,第i行

【bzoj2324】[ZJOI2011]营救皮卡丘 最短路-Floyd+有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6832504.html 题目描述 皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路. 火箭队一共有N个据点,据点之间存在M条双向道路.据点分别从1到N标号.小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘.为了方便起见,我们将真新镇视为0号据点,一开始K个人都在0号点. 由于火箭队的重重布防,要想摧毁K号据点,必须

【bzoj2055】80人环游世界 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend 题目描述 想必大家都看过成龙大哥的<80天环游世界>,里面的紧张刺激的打斗场面一定给你留下了深刻的印象.现在就有这么 一个80人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第i个人的游历路线为P1.P2......Pk(0≤k≤N),则P1<P2<......<Pk. 众所周知,中

[上下界费用流]JZOJ 3302 供电网络

Description 阿狸和桃子居住的世界里, 只有一个国家, 这个国家有很多城市, 每个城市直接由中央政府管辖.电力是这个国家的唯一能源, 但是每个城市的发电能力都不一样, 于是就产生了某些城市电力不足, 而某些城市却电力过剩的情况.阿狸作为国家的首席工程师, 阿狸的一项重要工作就是均衡整个国家的电力, 使得每个城市的电力都恰好没有剩余或不足.好在一些城市之间有电线可以输送电力, 这些电线都有自己的输送上限和下限, 并且输送电力的同时会产生大量的热.每条电线i 发出的热量一定是关于输送电量的

hdu 4862 Jump 上下界费用流

对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次. 然后若点u可到达点v,则连接即可.建成了一个上下界网络,将下界拆出去,求最大费用最大流就好. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<3

Acdream 1171 Matrix sum 上下界费用流

题目链接:点击打开链接 Matrix sum Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) SubmitStatisticNext Problem Problem Description sweet和zero在玩矩阵游戏,sweet画了一个N * M的矩阵,矩阵的每个格子有一个整数.zero给出N个数Ki,和M个数Kj,zero要求sweet选出一些数,满足从第 i 行至少选出了Ki

zoj 3231(上下界费用流)

题意:树上每个节点上有若干苹果,边上带权,问你最小费用使得书上的苹果方差最小. 思路:上下费用流问题,参考http://blog.csdn.net/qq564690377/article/details/8870587 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last m

P4043 [AHOI2014/JSOI2014]支线剧情 上下界费用流

题意: 有个人每次可以从1出发(可以无限次)  走有向边  耗费的时间为有向边的长度   问最少耗费的时间遍历所有的边至少一次 有点像滑雪那题  不过那题求得是最少的次数 这题很显然可以转化为上下界费用流  只要设置边的容量为1-inf 即可 注意: 上下界费用流的答案为: 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) 答案即为(求出的费用+原图中边的下界*边的费用) #include<bit