CF 331 E. Biologist

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;
}

转载于:https://www.cnblogs.com/hchhch233/p/10610271.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值