码迷,mamicode.com
首页 > 其他好文 > 详细

CF 331 E. Biologist

时间:2019-03-27 21:26:19      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:efi   next   没有   bio   its   不同   lin   add   mat   

CF 331 E. Biologist

题目描述

题目大意:有\(n\)个点,初始时每个点为黑色或者白色,你可以花费\(v_i\)的代价将一个点反色。然后你有许多计划,每个计划要求一个点集中的所有点为同种颜色。满足了一个计划就可以得到\(w_i\)相应的价值,某些计划如果没有被满足,还会付出\(g\)的代价。

感觉这个题有点最大权闭合子图的样子,\(g\)的额外代价也很鸡肋。

然后我们考虑这道题的反色操作。如果第\(i\)个点本来是白色的,那么我们连\((S,i,v_i)\),否则连\((i,T,v_i)\)。如果将这种边割了,就代表将这个点反色。

然后对于第\(i\)个计划,如果他要求的点集为白色,但是点集中的点\(x\)为黑色,则我们连\((i+n,x,\infty)\);反之连\((x,i+n,\infty)\)。然后对于白色计划连\((S,i+n,w_i+[i==friend]*g)\);对于黑色计划连\((i+n,T,w_i+[i==friend]*g)\)

如果\(S\to T\)有路径就代表有冲突了。

然后如果有不同颜色的计划的点集中有交,那么他们不可能同时选,于是连他们之间连一条\(\infty\)的边。然后我们可以优化一下这些边。

假设一个白色计划,它的点集中有白色点,那么我们也连\((i+n,x,\infty)\),黑色计划同理。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 15005

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n,m,g;
int col[N];
int v[N],fri[N],w[N];
int sex[N];
struct road {
    int to,next;
    int flow;
}s[N<<3];
int h[N],cnt=1;
int cur[N];
void add(int i,int j,int f) {
    s[++cnt]=(road) {j,h[i],f};h[i]=cnt;
    s[++cnt]=(road) {i,h[j],0};h[j]=cnt;
}

int S,T;
int dis[N];
queue<int>q;
bool bfs() {
    memset(dis,0x3f,sizeof(dis));
    q.push(S);
    dis[S]=0;
    while(!q.empty()) {
        int v=q.front();
        q.pop();
        for(int i=h[v];i;i=s[i].next) {
            int to=s[i].to;
            if(s[i].flow&&dis[to]>dis[v]+1) {
                dis[to]=dis[v]+1;
                q.push(to);
            }
        }
    }
    return dis[T]<1e9;
}

int dfs(int v,int maxf) {
    if(v==T) return maxf;
    int ret=0;
    for(int &i=cur[v];i;i=s[i].next) {
        int to=s[i].to;
        if(s[i].flow&&dis[to]==dis[v]+1) {
            int dlt=dfs(to,min(maxf,s[i].flow));
            s[i].flow-=dlt;
            s[i^1].flow+=dlt;
            ret+=dlt;
            maxf-=dlt;
            if(!maxf) return ret;
        }
    }
    return ret;
}

int dinic() {
    int ans=0;
    while(bfs()) {
        while(1) {
            memcpy(cur,h,sizeof(h));
            int tem=dfs(S,1e9);
            if(!tem) break;
            ans+=tem;
        }
    }
    return ans;
}
int sum=0;
int main() {
    n=Get(),m=Get(),g=Get();
    T=n+m+1;
    for(int i=1;i<=n;i++) col[i]=Get();
    for(int i=1;i<=n;i++) {
        v[i]=Get();
        if(!col[i]) add(S,i,v[i]);
        else add(i,T,v[i]);
    }
    for(int i=1;i<=m;i++) {
        sex[i]=Get(),w[i]=Get();
        sum+=w[i];
        int k=Get();
        while(k--) {
            int a=Get();
            if(sex[i]) add(a,i+n,1e9);
            else add(i+n,a,1e9);
        }
        fri[i]=Get();
    }
    for(int i=1;i<=m;i++) {
        if(sex[i]) add(i+n,T,w[i]+fri[i]*g);
        else add(S,i+n,w[i]+fri[i]*g);
    }
    cout<<sum-dinic();
    return 0;
}

CF 331 E. Biologist

标签:efi   next   没有   bio   its   不同   lin   add   mat   

原文地址:https://www.cnblogs.com/hchhch233/p/10610271.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!