zoukankan      html  css  js  c++  java
  • CF311E Biologist(最小割)

    题目链接

    CF:https://codeforc.es/contest/311/problem/E

    luogu:https://www.luogu.com.cn/problem/CF311E

    首先很套路地,我们可以先把所有的w[i]加起来,再考虑最小化代价

    即Ans = Σw[i] - Mincut

    我们可以把原来的字符串的点当作i(1 <= i <= n),m个要求也分别当作点i + n(1<= i <= m)

    首先我们考虑一下限制条件:

    1.如果不选这个要求,我们会损失w[i] 或 w[i] + g 设为f[i]

    2.如果选了这个要求,以这个要求1为例,设这个要求需要为1的若干个位置为S,设原字符串数组为str[i],则满足i属于集合S且str[i] == 0的i都要改变,即付出v[i]的代价

    3.相互矛盾的两个要求不能同时选,即某个要求需要位置i为0,另一个需要位置i为1,则这两个位置不能同时选

    建模

    1.我们考虑把str[i] == 1的点与S连边,流量为v[i],意即如果要变成0需要付出v[i]的代价,str[i] == 0则向T连边

    2.我们考虑把要求1的点向S连边,流量为f[i],然后向它要求的点连边,流量为inf,为么

    要这样连呢,因为这样连后我们会发现要么要把它向S的边割掉损失f[i],要么要把那些需要花代价变成1的点与T的连边割掉.意即要付出变成1需要花费的代价.要求0的点同理

    然后我们就满足了要求1,2,然后交上去就AC了.

    ??????为什么???我们不是还没满足限制3吗?数据水????

    这个地方是博主觉得这题最妙的地方,我们这样连边其实是满足限制3的

    为什么呢,放一张图相信大家都能看懂

    从图中可以看出要求1和要求2通过同一个点x形成了一条从S到T联通的路径,由于最小割要割断S和T的路径所以互相矛盾的要求不可能同时选

    最优性可以由最小割算法本身保证

    所以就做完这道题啦

    代码如下

    /*CF311E Biologist*/
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    int read(){
    	char c = getchar();
    	int x = 0;
    	while(c < '0' || c > '9')		c = getchar();
    	while(c >= '0' && c <= '9')		x = x * 10 + c - 48,c = getchar();
    	return x;
    }
    const int maxn = 1e6 + 10;
    struct Edge{
    	int nxt,point,flow;
    }edge[maxn<<1];
    int S,T,dep[maxn],cur[maxn],head[maxn],q[maxn],tot,n,m;
    void add(int x,int y,int flow){
    	edge[++tot].nxt = head[x];edge[tot].point = y;edge[tot].flow = flow;head[x] = tot;
    	edge[++tot].nxt = head[y];edge[tot].point = x;edge[tot].flow = 0;	head[y] = tot;
    }
    bool bfs(){
    	for(int i = S; i <= T; ++i)		cur[i] = head[i],dep[i] = 0;
    	dep[S] = 1;
    	int l = 1,r = 0;
    	q[++r] = S;
    	while(l <= r){
    		int x = q[l++];
    		for(int i = head[x]; i ; i = edge[i].nxt){
    			int y = edge[i].point;
    			if(!dep[y] && edge[i].flow){
    				dep[y] = dep[x] + 1;
    				q[++r] = y;
    			}
    		}
    	}
    	return (dep[T] != 0);
    }
    int Dinic(int x,int flow){
    	if(x == T || !flow)	return flow;
    	int rest = flow,k;
    	for(int i = cur[x]; i ; i = edge[i].nxt){
    		int y = edge[i].point;
    		cur[x] = i;
    		if(edge[i].flow && dep[y] == dep[x] + 1){
    			k = Dinic(y,min(edge[i].flow,rest));
    			if(!k)	dep[y] = 0;
    			rest -= k;
    			edge[i].flow -= k;
    			edge[i^1].flow += k;
    		}
    	}
    	return flow - rest;
    }
    int v[maxn];
    int str[maxn];
    int main(){
    	tot = 1;
    	n = read(),m = read();int g = read();
    	T = n + m + 1;
    	for(int i = 1; i <= n; ++i)		str[i] = read();
    	for(int i = 1; i <= n; ++i){
    		v[i] = read();
    		if(str[i] == 1)		add(S,i,v[i]);
    		else	add(i,T,v[i]);
    	}
    	ll ans = 0;
    	for(int i = 1; i <= m; ++i){
    		int opt = read();int w = read(),k = read();
    		ans += w;
    		for(int j = 1; j <= k; ++j){
    			int x = read();
    			if(opt)		add(n+i,x,1e9);
    			else	add(x,n+i,1e9);
    		} 
    		int t = read();
    		if(opt)		add(S,n+i,w+g*t);
    		else	add(n+i,T,w+g*t);
    	} 
    	while(bfs())	ans -= Dinic(S,1e9);
    	cout<<ans<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    [转]windows7远程桌面连接失败:发生身份验证错误。要求的函数不受支持
    SNMP协议学习笔记
    Sublime for MacOS 使用技巧
    Git常用操作
    罗技K380连接Win10(MacBookPro双系统)系统失败
    Git知识点汇总
    开发工作中提高效率的一些方式
    css
    IO多路复用
    进程
  • 原文地址:https://www.cnblogs.com/y-dove/p/13750792.html
Copyright © 2011-2022 走看看