【CF311E】biologist

题目大意

先放链接
简述一下:
有n个布尔变量,开始时分别是0或1。你可以改变这些变量,改变(0变1,1变0)第i个变量的代价是v[i]
现在有m个限制,形如a,b,x1,x2,x3…,xk,表示希望x1-xk都是a(a为0或1),都满足后可以获得b的价值
有一些限制如果没有满足要倒扣g的价值,g对于所有限制是一个相同的值
求最后能获得的最大价值

思路

一眼网络流
一个错误的思路:假设我们只考虑1,那么每个人到s连边,每个人到ta希望是1的连边,每个1(如果要改)向t连边。总和减最小割。但是这样无法考虑1和0。考虑使得1和0不能同时选(也不能同时不选),于是不能都不割,也不能都割,所以把是1和是0作为两个点,使他们在一个路径上。这样无法表示不满足某个限制。
想不粗来了qwq
于是注意到我们有一些条件没有用:每个限制一定是某些全是1/全是0,于是其实限制是两类
那么把变量放中间,希望是1的限制放在上面连s,希望是0的放下面连t,每个和他所限制的变量连边,这样可以保证每个点所构成的通路一定是一边(上边/下边)都被割了,这样可以表示最终是1/0
现在最后考虑改变变量的代价:假设这个变量最开始是1,那么我们希望这个代价是加在他不是1上的,就是加在他割去表示1那边的时候。那么我们让他割去1之后仍然联通,于是把他跟1那边的虚拟点联通(1的话就是s)。
于是我们解决了这个问题

总结

此题解法可以类比如何使得两个东西不能同时选,不能同时不选
注意观察题目是否有隐藏性质没有使用

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <math.h>
#include <algorithm>
#include <queue>
#include <vector>
#define MAXN 10050
#define INF (1<<28)
using namespace std;
int s, t, n, m, g, sex[MAXN], v[MAXN], ans, level[MAXN<<3], q[MAXN<<3], cnt;
struct node{
    int v, c;
    node *next, *rev;
}pool[MAXN<<6], *h[MAXN<<4], *cur[MAXN<<4];
inline void addedge(int u, int v, int c){
    node *p1 = &pool[cnt++], *p2 = &pool[cnt++];
    *p1 = node{v, c, h[u], p2}, h[u] = p1;
    *p2 = node{u, 0, h[v], p1}, h[v] = p2;
}
// s 0 t 1
bool bfs(){
    int front = 0, rear = 1;
    memset(level, 0, sizeof(level));
    level[s] = 1;
    q[0] = s;
    while(front < rear){
        int u = q[front++];
        if(u == t) return 1;
        for(node *p = h[u]; p; p = p->next){
            if(!level[p->v] && p->c){
                q[rear++] = p->v;
                level[p->v] = level[u]+1;
            }
        }
    }
    return 0;
}
int dfs(int u, int t, int f){
    if(u == t) return f;
    int flow = 0, F, Min;
    for(node *&p = cur[u]; p; p = p->next){
        if(level[p->v] == level[u]+1 && p->c){
            Min = min(f-flow, p->c);
            F = dfs(p->v, t, Min);
            flow += F;
            p->c -= F;
            p->rev->c += F;
            if(flow == f) return flow;
        }
    }
    return flow;
}
int Dinic(){
    int ret = 0;
    while(bfs()){
        for(int i = s; i <= t; i++) cur[i] = h[i];
        ret += dfs(s, t, INF);
    }
    return ret;
}
int main(){
    scanf("%d%d%d", &n, &m, &g);
    t = n+m+1;
    int w, k, exp, fri, cur;
    for(int i = 1; i <= n; i++) scanf("%d", &sex[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &exp, &w, &k);
        ans += w;
        for(int j = 1; j <= k; j++) {
            scanf("%d", &cur);
            if(exp) addedge(cur+m, i, INF);
            else addedge(i, cur+m, INF);
        }
        scanf("%d", &fri);
        w += g*fri;
        if(exp) addedge(i, t, w); 
        else addedge(s, i, w);
    }
    for(int i = 1; i <= n; i++) {
        if(sex[i]) addedge(i+m, t, v[i]);
        else addedge(s, i+m, v[i]);
    } 
    int cut = Dinic();
    //cout<<cut<<' ';
    ans -= cut;
    printf("%d", ans);
    return 0;
}
posted @ 2018-06-20 18:26  hychyc1  阅读(113)  评论(0编辑  收藏  举报