Codefores #185E (div1) Biologist

Codefores #185E (div1) Biologist

tags: ACM–>图论–>网络流–>最小割


题目大意:

   SmallR有n只狗,第i 只狗最初性别为 sexi , 改变其性别的代价为 vi RMB。

  有m个人,对第j个人,如果某些狗 {i1,i2,,ikj} 的性别都为 asexj ,SmallR将得到 wj RMB, 否则,当第j个人是SmallR的好朋友时,SmallR将付出 g RMB.

  问SmallR最多能得到多少RMB(可能为负)。

数据范围

1n104,0m2000,0g,vi,wj104,0kj10,sexi,asexj{0,1}

解法

建图

  建立源点S(表示性别0), 和汇点T(表示性别1), 从S分别建一条容量为 vi 的边连向所有最初性别为1的狗, 同样所有最初性别为0的狗建一条容量为 vi 的边连向T。
  对于每个人i, 新建一个结点u, 如果希望狗的性别 asexi 为0,则将一条容量为 wi 的边从S指向u, 再分别建从u指向期望的狗的结点,容量为 的边;反之,如果希望狗的性别 asexi 为1,建一条从u指向T,容量为 wi 的边, 再分别见从期望的每条狗指向u, 容量为 的边.

思路

将所有 wi 加起来,再减去最小损失的钱数,就是答案。即将最大获利变为最小损失。那么,改变一只狗的性别损失 vi RMB, 没有满足某个人的需求, 将损失 wi RMB(如果是好朋友,则损失 wi+g RMB。在上面建立的图中,跑最小割。因为对于每一条从S到T的道路, 必然是 S->人->狗->T 或则 S->狗->人->T, 其中中间条边的容量是 , 因此在最小割中不用考虑这条边。所以在最小割中如果S->人人->T)在割集中,即不满足某个人的需求,则对应的狗改不改变性别皆可;反之对应的所有狗与T(S)的连边都在割集中,表示满足了某人的连线。所以最小割的容量表示了最小的损失。由此得出答案。

官方题解

Obviously, It is about min-cut, which can be solved by max-flow. So, this problem can regarded as the minimum of losing money if we assume SmallR can get all the money and get a total money(sum of wi)at first Define that, in the min-cut result, the dogs which are connected directly or indirectly to S are 0-gender.otherwise, those to T are 1-gender.We can easily find that the point of a initial-0-gender dog should get a vi weight edge to S.On the other way, initial-1-gender to T. Then, consider the rich men.As to each of rich men, he can appoint only one gender and some dogs.if any one dog he appoint is not the one appointed gender in the result, he can’t give SmallR money.How to deal with the rich men in the graph is a difficulty.We can do this, make a new point for a rich man.Then, link the man’s point to all points of his dogs by max enough weigh edges(which we can’t cut in the min-cut algorithm), and link the man’s point to S or T (which depend on that the man’s appointed gender is 0 or 1) with a edge of wi weight. lastly run the min-cut(max-flow), we will get the minimum money we will lose. The answer is TotalMoney-LosedMoney. BTW, the issue of g is a piece of cake, we could add it to every special wi but not add it to the total money.

代码

#include <bits/stdc++.h>
#define INF 1000000007
#define MP make_pair
#define FI first
#define SE second
#define PB push_back
#define VI vector<int>
const double EPS = 1e-7, PI = acos(-1.0);
using namespace std;
typedef long long LL;
typedef pair <int, int> P;
const int NUM = 10010;
const int MAXV = 2 * NUM, MAXE = MAXV * 4;
struct edge {int next, to, cap;} e[MAXE];
int head[MAXV], tot, V;
void gInit() {memset(head, -1, sizeof(head)); tot = 0; V = 0;}
void add_edge(int u, int v, int cap)
{
    e[tot] = (edge) {head[u], v, cap}; head[u] = tot++;
    e[tot] = (edge) {head[v], u, 0}; head[v] = tot++;
}

int h[MAXV];
int numh[MAXV];
int iter[MAXV];
int Prev[MAXV];
int sap(int s, int t)
{
    memset(h, 0, sizeof(h));
    memset(numh, 0, sizeof(numh));
    memset(Prev, -1, sizeof(Prev));
    for(int i = 0; i < V; ++i) iter[i] = head[i];
    numh[0] = V;
    int u = s, max_flow = 0, i;
    while(h[s] < V)
    {
        if(u == t)
        {
            int flow = INF, neck = -1;
            for(u = s; u != t; u = e[iter[u]].to)
            {
                if(flow > e[iter[u]].cap)
                {
                    neck = u;
                    flow = e[iter[u]].cap;
                }
            }
            for(u = s; u != t; u = e[iter[u]].to)
            {
                e[iter[u]].cap -= flow;
                e[iter[u] ^ 1].cap += flow;
            }
            max_flow += flow;
            u = neck;
        }
        for(i = iter[u]; ~i; i = e[i].next)
            if(e[i].cap > 0 && h[u] == h[e[i].to] + 1)
                break;
        if(i != -1)
        {
            iter[u] = i;
            Prev[e[i].to] = u;
            u = e[i].to;
        }
        else
        {
            if(0 == --numh[h[u]]) break;
            iter[u] = head[u];
            for(h[u] = V, i = head[u]; ~i; i = e[i].next)
            {
                if(e[i].cap > 0)
                {
                    h[u] = min(h[u], h[e[i].to]);
                }
            }
            ++h[u];
            ++numh[h[u]];
            if(u != s) u = Prev[u];
        }
    }
    return max_flow;
}

int n, m, g;
int sex[NUM];
int cost[NUM];
int asex, wi, ki, gf;
int ans, s, t;
int main()
{
#ifdef ACM_TEST
    freopen("in.txt", "r", stdin);
#endif
    scanf("%d%d%d", &n, &m, &g);
    for(int i = 1; i <= n; ++i) scanf("%d", &sex[i]);
    for(int i = 1; i <= n; ++i) scanf("%d", &cost[i]);
    gInit();
    V = n + m + 2;
    s = 0, t = V - 1;
    for(int i = 1; i <= n; ++i)
    {
        if(sex[i] == 0)
        {
            add_edge(s, i, cost[i]);
        }
        else
        {
            add_edge(i, t, cost[i]);
        }
    }
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d%d%d", &asex, &wi, &ki);
        for(int j = 0, u; j < ki; ++j)
        {
            scanf("%d", &u);
            if(asex == 0) add_edge(i + n, u, INF);
            else add_edge(u, i + n, INF);
        }
        scanf("%d", &gf);
        ans += wi;
        if(gf) wi += g;
        if(asex == 0) add_edge(s, i + n, wi);
        else add_edge(i + n, t, wi);
    }
    printf("%d\n", ans - sap(s, t));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值