• BZOJ4177Mike的农场——最小割


    题目描述

     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

    提示

     对于100的数据,n <= 5000, m <= 5000, k <= 5000, a = 0 or 1。

    我们需要对每个围栏进行决策——选牛还是选羊。那么就将源点看成牛,将汇点看成羊,对于每个围栏分别与源汇点连边,流量为对应选牛或羊的代价。对于每个规则将对应点之间连双向边,流量为对应代价。对于特殊规则,如果是选牛的就新建一个节点与源点连边,流量为对应收益,反之则与汇点连边,然后再将这个点与特殊规则指定集合中的点分别连边,流量为$INF$。最后答案为所有收益之和$-$最小割。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define INF 1000000000
    using namespace std;
    int head[40000];
    int next[160000];
    int to[160000];
    int val[160000];
    int d[40000];
    int q[40000];
    int n,m,k;
    int s,x,y,v;
    int a[6000];
    int b[6000];
    int tot=1;
    int ans;
    int S,T;
    void add(int x,int y,int v)
    {
    	tot++;
    	next[tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;
    	val[tot]=v;
    	tot++;
    	next[tot]=head[y];
    	head[y]=tot;
    	to[tot]=x;
    	val[tot]=0;
    }
    bool bfs(int S,int T)
    {
    	int r=0;
    	int l=0;
    	memset(q,0,sizeof(q));
    	memset(d,-1,sizeof(d));
    	q[r++]=S;
    	d[S]=0;
    	while(l<r)
    	{  
    		int now=q[l];
    		for(int i=head[now];i;i=next[i])
    		{
    			if(d[to[i]]==-1&&val[i]!=0)
    			{
    				d[to[i]]=d[now]+1;
    				q[r++]=to[i];
    			}
    		}
    		l++;
    	}
    	return d[T]!=-1;
    }
    int dfs(int x,int flow)
    {
    	if(x==T)
    	{
    		return flow;
    	}
    	int now_flow;
    	int used=0;
    	for(int i=head[x];i;i=next[i])
    	{
    		if(d[to[i]]==d[x]+1&&val[i]!=0)
    		{
    			now_flow=dfs(to[i],min(flow-used,val[i]));
    			val[i]-=now_flow;
    			val[i^1]+=now_flow;
    			used+=now_flow;
    			if(now_flow==flow)
    			{
    				return flow;
    			}
    		}
    	}
    	if(used==0)
    	{
    		d[x]=-1;
    	}
    	return used;
    }
    void dinic()
    {
    	while(bfs(S,T)==true)
    	{
    		ans-=dfs(S,0x3f3f3f);
    	}
    }
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);
    	S=n+k+1;
    	T=S+1;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		add(S,i,a[i]);
    		ans+=a[i];
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&b[i]);
    		add(i,T,b[i]);
    		ans+=b[i];
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&v);
    		add(x,y,v);
    		add(y,x,v);
    	}
    	for(int i=1;i<=k;i++)
    	{
    		scanf("%d%d%d",&s,&y,&v);
    		ans+=v;
    		if(!y)
    		{
    			add(S,n+i,v);
    		}
    		else
    		{
    			add(n+i,T,v);
    		}
    		for(int j=1;j<=s;j++)
    		{
    			scanf("%d",&x);
    			if(!y)
    			{
    				add(n+i,x,INF);
    			}
    			else
    			{
    				add(x,n+i,INF);
    			}
    		}
    	}
    	dinic();
    	printf("%d",ans);
    }
  • 相关阅读:
    static的全部用法收集整理
    文思创新复试及一些自己的思考
    “一碗牛肉面”引发的管理难题
    信必优面试实录
    我做PM(项目经理)这段时间...
    什么是面向对象?
    沟通
    体会Bind和Eval的不同用法
    北京艾德思奇科技有限公司面试实录
    今天去sony公司面试实录
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10572027.html
Copyright © 2020-2023  润新知