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想知道他该在哪些围栏中饲养什么动物才能使得总收益最大,为了简化问题,你只需要输出最大收益。

    思路:最小割。

    先把所有的收益加起来,然后建图跑最小割,最小割就是最小损失的收益,总收益-最小损失就是答案

    对于每个围栏建一个点,由S向每个点连a[i]的边,由每个点再向T连b[i]的边,最终与S相连,那么它就割掉了连向T的边,表示最终这个围栏养牛,将损失养羊的收益a[i],与T相连同理。

    对于规律(i,j,k),就在(i,j)之间连权值为k的双向边,其实就是组合收益的建图

    对于规则(S,a,b),就新建一个点,并向S中所有点连inf的边,如果是牛就从源向新点连一条权值为b的边,否则向汇连。

    以都选牛有收益为例,当两个点都选了牛,就会割掉羊的边,那么这条新边就不会被割了,我们就得到了b的收益。


    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=20010,maxm=1000010,maxq=1000000,inf=(int)1e9;
    using namespace std;
    int n,m,k,a[maxn],b[maxn],dis[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot=1,S=0,T=maxn-1,q[maxq+10],head,tail,ans,res;char ch;
    void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    void ins(int a,int b,int c){add(a,b,c),add(b,a,0);}
    
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    
    bool bfs(){
    	memset(dis,-1,sizeof(dis));
    	q[1]=S,head=0,tail=1,dis[S]=0;
    	do{
    		if (++head>maxq) head=1;
    		int x=q[head];
    		for (int y=now[x];y;y=pre[y])
    			if (dis[son[y]]==-1&&val[y]){
    				if (++tail>maxq) tail=1;
    				dis[son[y]]=dis[x]+1,q[tail]=son[y];
    			}
    	}while (head!=tail);
    	return dis[T]>0;
    }
    
    int find(int x,int low){
    	int res=0,y;
    	if (x==T) return low;
    	for (y=now[x];y;y=pre[y]){
    		if (dis[son[y]]!=dis[x]+1||!val[y]) continue;
    		int tmp=find(son[y],min(low,val[y]));
    		val[y]-=tmp,val[y^1]+=tmp,res+=tmp,low-=tmp;
    		if (!low) break;
    	}
    	if (!y) dis[x]=-1;
    	return res;
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&k);
    	for (int i=1;i<=n;i++) read(a[i]),ins(S,i,a[i]),ans+=a[i];
    	for (int i=1;i<=n;i++) read(b[i]),ins(i,T,b[i]),ans+=b[i];
    	for (int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),add(x,y,z),add(y,x,z);
    	for (int i=1,t,x,y;i<=k;i++){
    		read(t),read(x),read(y),ans+=y;
    		if (!x){
    			ins(S,++n,y);
    			for (int j=1,z;j<=t;j++) read(z),ins(n,z,inf);
    		}
    		else{
    			ins(++n,T,y);
    			for (int j=1,z;j<=t;j++) read(z),ins(z,n,inf);
    		}
    	}
    	while (bfs()) res+=find(S,inf);
    	printf("%d
    ",ans-res);
    	return 0;
    }


  • 相关阅读:
    什么是webview
    juqery.fn.extend和jquery.extend
    LeetCode
    5. Longest Palindromic Substring
    42. Trapping Rain Water
    11. Container With Most Water
    621. Task Scheduler
    49. Group Anagrams
    739. Daily Temperatures
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/thythy/p/5493580.html
Copyright © 2011-2022 走看看