首页 > 其他分享 >【题解】CF311E Biologist题解

【题解】CF311E Biologist题解

时间:2024-04-11 09:59:55浏览次数:15  
标签:要求 dist int 题解 flow edge CF311E Biologist now

CF311E Biologist题解

非常好的一道最小割。

思路

首先看到每一个位置又会有 \(0 1\) 两种情况,然后要满足一些要求,求最大收益,考虑类似于 P4313 文理分科P1361 小M的作物 这种集合划分的建图方法,也就是要用最小割求解。

由于我们要求的是最大收益,所以我们要先明确要最小化什么,然后用 所有可能获得的收益 减去 最小割 就是 最大收益

根据题意,我们首先希望反转某个位置的代价尽可能小,同时被割去的收益和朋友的赔礼也应该尽可能小,也就是要最小化 反转的代价 不能选的要求朋友的赔礼

每一个位置有 \(0 1\) 两种情况,考虑将所有一开始为 \(1\) 的点放在左边 ( \(1\) 集合),为 \(0\) 的点放在右边 ( \(0\) 集合),分别于 \(S,T\) 连容量为 \(v_i\) 的边。

其中,割掉 \(1\) 集合中的点 与 \(S\) 相连的边则表示这个点属于 \(0\) 这个集合,同样,割掉 \(0\) 集合中的点 与 \(T\) 相连的边则表示这个点属于 \(1\) 集合。

反转某个位置的代价考虑完了,现在开始解决那些要求。

先考虑 要求每个位置都为 \(1\) 的要求。

现在考虑这样一种情况。

其中 2 3 4 属于 \(1\) 集合, 1 5 属于 \(0\) 集合。 同时我们要求 2 3 都为 \(1\) 可以获得 \(w_i\) 的收益。

考虑这么建图:

如果 2 3 都为 \(1\) ,则不会割去任何边。如果 2 3 有一个不为 \(1\) ,则会割去 \(w_i\) 和那些点反转的边,满足题意。

现在我们要求 1 4 5 都为 \(0\) 可以获得 \(w_i\) 收益。

也就是这种情况:

同样的,因为我们不能割去 \(inf\) 的边,所以,如果我们不想割掉这个要求,就必须让 4 属于 \(0\) 集合,也就是得割去 \(2\) 那条边,否则就必须割去 \(w_i\) 。

现在只剩下朋友的要求没有解决了。

很简单,如果某个要求是朋友提出的,只需要在 \(w_i\) 上加上 \(g\) 。

分析这样做的正确性:我们的答案为 \(\sum\limits_{i=1}^m{w_i}-最小割\) ,再加上朋友的要求之后,如果某个要求被割掉了,答案同样也会减去 \(g\) ,满足题意。

综上所述:

S -> 一开始为1的点 连容量为 vi 的边。
一开始为0的点 -> T 连容量为 vi 的边。

对于每个要求:
    新建一个点a。
    
    如果要求每个数字为1:
      S -> a 容量为 wi (+pi)
      a -> 所以要求的点 容量为 inf 的边

    如果要求每个数字为0:
      b -> T 容量为 wi (+pi)
      所以要求的点 -> b 容量为 inf 的边

最后答案为 \(\sum\limits_{i=1}^m{w_i}-最小割\) 。

代码

#include<bits/stdc++.h>
using namespace std;
const int MX_N=50100,MX_M=500100;
const int INF=0x3f3f3f3f;
struct node{
    int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
    node &i=edge[edge_cnt];
    i.w=w,i.to=y,i.next=head[x];
    head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
    Add(x,y,w),Add(y,x,0);
}
int s=0,t=MX_N-1;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
    for(int i=0;i<MX_N;i++)  cur[i]=head[i],dist[i]=-1;
    queue<int > qu;qu.push(s);dist[s]=0;
    while(!qu.empty()){
        int now=qu.front();qu.pop();
        for(int i=head[now];i!=-1;i=edge[i].next){
            int to=edge[i].to;
            if(dist[to]==-1&&edge[i].w){
                dist[to]=dist[now]+1;
                qu.push(to);
            }
        }
    }
    return dist[t]!=-1;
}
int dfs(int now,int flow){
    if(now==t)  return flow;
    int left=flow;
    for(int &i=cur[now];i!=-1;i=edge[i].next){
        int to=edge[i].to,w=edge[i].w;
        if(dist[to]==dist[now]+1&&w){
            int cur_flow=dfs(to,min(left,w));
            left-=cur_flow;
            edge[i].w-=cur_flow;
            edge[i^1].w+=cur_flow;
            if(left==0)  break;
        }
    }
    if(flow==left)  dist[now]=-1;
    return flow-left;
}
int dinic(){
    int sum=0;
    while(bfs()){
        sum+=dfs(s,INF);
    }
    return sum;
}
bool st[10100]={0};
signed main(){
    memset(head,-1,sizeof(head));
    //=======================================================
    int n,m,g;scanf("%d%d%d",&n,&m,&g);
    for(int i=1;i<=n;i++)  scanf("%d",&st[i]);
    for(int i=1;i<=n;i++){
        int vi;scanf("%d",&vi);
        if(st[i]){
            add(s,i,vi);
        }
        else{
            add(i,t,vi);
        }
    }
    int sum=0;
    for(int i=1;i<=m;i++){
        int op,wi,ki;scanf("%d%d%d",&op,&wi,&ki);sum+=wi;
        for(int j=1;j<=ki;j++){
            int xi;scanf("%d",&xi);
            if(op)  add(i+n,xi,INF);
            else  add(xi,i+n,INF);
        }
        int fri;scanf("%d",&fri);
        if(op){
            add(s,i+n,wi+fri*g);
        }
        else{
            add(i+n,t,wi+fri*g);
        }
    }
    printf("%d",sum-dinic());
    //=======================================================
    return 0;
}//CF311E

求过,求关注。

标签:要求,dist,int,题解,flow,edge,CF311E,Biologist,now
From: https://www.cnblogs.com/DaiFu/p/18128111

相关文章

  • 【题解】CF1187G Gang Up
    【题解】CF1187GGangUp题意给定一个图,有\(k\)个人要走到\(1\)号节点,问最小花费。解法一眼丁真,鉴定为费用流。考虑到这道题花费会与时间有关,所以分层图,启动!。按时刻分层,现在分析每个人在第\(k\)时刻的动向:1.呆着不动。2.走到下一个节点。对于动向\(1\),从时......
  • 洛谷 P6692 题解
    洛谷P6692出生点题意简述\(n\)行\(m\)列构成\(nm\)个格点,在其中指定\(k\)个障碍点。每行、每列之间的距离为\(1\),每次任意选取两个非障碍点,计算这两个点的曼哈顿距离,求所有选法的距离之和。分析由容斥原理,答案为「任意两点之间的距离之和」\(-\)「每个障碍点到其他......
  • CF358B Dima and Text Messages 题解
    大家好,我不喜欢string,所以我选择用char来写。题目传送门,但不是洛谷。吐槽一下,这个翻译翻译的并不好,翻译中并没有说明“爱心”是指<3,还是得去自己翻。正文将读入的单词连在一起,并穿插爱心,注意这里首尾都是爱心,需要手动补充。最后将得到的序列与输入的字符串进行比对即可。......
  • 2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(判断题)
    2024年3月Python编程等级考试一级真题解析判断题(共10题,每题2分,共20分)26、turtle画布的坐标系原点是在画布的左上角答案:错考点分析:考查turtle相关知识,turtle画布坐标系是在画布的中点,答案错误27、Python变量名区分大小写,book和BOOK不是同一个变量答案:对考点分析:考查......
  • CF1250A Berstagram 题解
    题面。题意描述的很清楚,这里就不多赘述。思路看题,对于每个\(a_i\),若\(b_j=a_i\),则将\(b_j\)与\(b_{j-1}\)的值调换(若\(j=1\),则序列不变)。一开始想的是最直接的暴力,复杂度为\(O(nm)\),虽然开了三秒的时限,但\(4\times10^{10}\)的数据明显不是三秒钟就能解决的,含恨倒在第......
  • P8791 [蓝桥杯 2022 国 AC] 内存空间 题解
    题面一道比较简单模拟题,但是要分类讨论一.读完题你应该知道的1.输入一共有T+1行,输入含有空格。(处理1)2.对于每一行变量定义的语句,只会出现一种变量类型,type只可能是int或long,只有一个分号。(处理1,处理2)3.统计内存过程中用B做单位,保证一定有输出,但在输出时要换......
  • CF1681C Double Sort 题解
    一道普及-我写了两个半小时题面。需要注意的是,每次交换需要将a和b两个数组同时交换,因此便可以想到唯一可行情况:a,b序列数字间的大小关系必须一致。举个例子2462131317970612在上面的例子中,两个序列中任意\(i\)和\(j\)满足\(a_i\lea_j\)时\(b_i......
  • CF958F1 Lightsabers (easy) 题解
    题面。不好意思,当我看到\(1\len\le100\),\(1\lem\len\)的那一刻,我承认我心动了。题目没翻译,用翻译软件翻译了才看懂。思路依据题意直接模拟即可。这里我用了三层循环来模拟。第一层为\(len\),表示长度;第二层为\(from\),表示出发点,此时需要遍历的区间的终点\(to=from......
  • CF1040B Shashlik Cooking 题解
    题面。看到这道题的第一眼,就想到用分块思想来解决。思路我们知道,当对任意一个\(i\)进行翻转时,区间\([i-k,i+k]\)内的所有元素都会翻转,每次翻转的总个数为\(2\timesk+1\)。因此,我们可以将所有烤串分成长度为\(len=2\timesk+1\)的\(block=n\divlen\)块,用数组\(L......
  • CF158C Cd and pwd commands 题解
    题面。大模拟,但是有坑点。思路依照题意模拟。用一个字符串\(out\)记录在进行了\(i\)次操作后如果要输出输出的东西,字符串\(in\)和\(s\)来分别记录输入的操作及操作类型。由于输出的第一个字符一定是/,所以可以直接将\(out\)的初始化定为out="/"。这样子可以省去......