zoukankan      html  css  js  c++  java
  • 【bzoj4177】Mike的农场 网络流最小割

    题目描述

    Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响。不过同时Mike也发现k条特殊的规则(S, a, b),表示如果S中所有牲畜围栏中都养的是动物a,那么Mike可以获得b的额外收入。现在Mike想知道他该在哪些围栏中饲养什么动物才能使得总收益最大,为了简化问题,你只需要输出最大收益。

    输入

    第一行三个整数n、m、k,表示一共有n个围栏,m条规律,k条规则。

    第二行有n个整数,表示a[i]。

    第三行有n个整数,表示b[i]。

    接下来m行,每行有三个整数(i, j, k)表示一条规则。

    再接下来k行,每行一开始有三个整数t、a和b,表示一条规则(S, a, b),其中S的大小为t,接下来t个整数表示S中的元素(a为0表示全为牛,a为1表示全为羊)。

    输出

    输出一个整数ans,表示最大收益。

    样例输入

    4 2 1
    1 2 3 1
    2 3 1 2
    1 2 3
    1 3 2
    2 0 100 1 2

    样例输出

    108


    题解

    经典的网络流最小割建模

    建模方法:

    S向x连边,容量为a[x];x向T连边,容量为b[x];

    如果两个选择不同则要付出代价,那么在它们之间连双向边,容量为代价k;

    如果P集合内全部选择S端则获得额外收益,那么建一个新点p代表集合,S向p连边,容量为收益,p向P中每个点连边,容量为$infty$;全部选择T端同理,每个点连p,p连T。

    跑最小割,答案为所有收益之和-最小割。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #define N 10010
    #define M 1000010
    #define inf 1 << 30
    using namespace std;
    queue<int> q;
    int head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
    inline void add(int x , int y , int z)
    {
    	to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    	to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
    	int x , i;
    	memset(dis , 0 , sizeof(dis));
    	while(!q.empty()) q.pop();
    	dis[s] = 1 , q.push(s);
    	while(!q.empty())
    	{
    		x = q.front() , q.pop();
    		for(i = head[x] ; i ; i = next[i])
    		{
    			if(val[i] && !dis[to[i]])
    			{
    				dis[to[i]] = dis[x] + 1;
    				if(to[i] == t) return 1;
    				q.push(to[i]);
    			}
    		}
    	}
    	return 0;
    }
    int dinic(int x , int low)
    {
    	if(x == t) return low;
    	int temp = low , i , k;
    	for(i = head[x] ; i ; i = next[i])
    	{
    		if(val[i] && dis[to[i]] == dis[x] + 1)
    		{
    			k = dinic(to[i] , min(temp , val[i]));
    			if(!k) dis[to[i]] = 0;
    			val[i] -= k , val[i ^ 1] += k;
    			if(!(temp -= k)) break;
    		}
    	}
    	return low - temp;
    }
    int main()
    {
    	int n , m , k , i , x , y , z , sum = 0;
    	scanf("%d%d%d" , &n , &m , &k) , s = 0 , t = n + k + 1;
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , add(s , i , x) , sum += x;
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , add(i , t , x) , sum += x;
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
    	for(i = 1 ; i <= k ; i ++ )
    	{
    		scanf("%d%d%d" , &x , &y , &z) , sum += z;
    		if(y)
    		{
    			add(i + n , t , z);
    			while(x -- ) scanf("%d" , &y) , add(y , i + n , inf);
    		}
    		else
    		{
    			add(s , i + n , z);
    			while(x -- ) scanf("%d" , &y) , add(i + n , y , inf);
    		}
    	}
    	while(bfs()) sum -= dinic(s , inf);
    	printf("%d
    " , sum);
    	return 0;
    }
    

     

  • 相关阅读:
    java mybatis
    java influx DB工具类
    java redisUtils工具类很全
    java 任务定时调度(定时器)
    java 线程并发(生产者、消费者模式)
    java 线程同步、死锁
    Redis 集群版
    Redis 单机版
    linux下配置zookeeper注册中心及运行dubbo服务
    vue搭建前端相关命令
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7493249.html
Copyright © 2011-2022 走看看