• BZOJ 4177: Mike的农场( 最小割 )


    显然是最小割...

    对于规律(i, j, k) i,j 互相连边, 容量为k

    对于规则(S, a, b) 新建一个点x, x与S中每个点连一条弧, 容量+∞, 然后再根据a决定x与源点或汇点连边. 

    跑最大流, 用总收益减去就是答案了...挺好想的一道题...

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 10100;
    const int INF = 10000000;
    
    struct edge {
    	int to, cap;
    	edge *next, *rev;
    } E[1000000], *pt = E, *head[maxn];
    
    inline void add(int u, int v, int w) {
    	pt->to = v; pt->cap = w;
    	pt->next = head[u]; head[u] = pt++;
    }
    inline void addedge(int u, int v, int w) {
    	add(u, v, w); add(v, u, 0);
    	head[u]->rev = head[v];
    	head[v]->rev = head[u];
    }
    
    int S, T, N, cnt[maxn], h[maxn];
    edge *cur[maxn], *p[maxn];
    
    int maxFlow() {
    	memset(cnt, 0, sizeof cnt); cnt[0] = N;
    	memset(h, 0, sizeof h);
    	for(int i = 0; i < N; i++) cur[i] = head[i];
    	edge* e;
    	int flow = 0;
    	for(int x = S, A = INF; h[S] < N; ) {
    		for(e = cur[x]; e; e = e->next)
    		    if(e->cap && h[e->to] + 1 == h[x]) break;
    		if(e) {
    			cur[x] = p[e->to] = e;
    			A = min(A, e->cap);
    			x = e->to;
    			if(x == T) {
    				for(; x != S; x = p[x]->rev->to) {
    					p[x]->cap -= A;
    					p[x]->rev->cap += A;
    				}
    				flow += A;
    				A = INF;
    			}
    		} else {
    			if(!--cnt[h[x]]) break;
    			h[x] = N;
    			for(e = head[x]; e; e = e->next) if(e->cap && h[e->to] + 1 < h[x]) {
    				h[x] = h[e->to] + 1;
    				cur[x] = e;
    			}
    			cnt[h[x]]++;
    			if(x != S) x = p[x]->rev->to;
    		}
    	}
    	return flow;
    }			
    
    int main() {
    	
    	int ans = 0;
    	int n, m, k; scanf("%d%d%d", &n, &m, &k);
    	S = 0; T = n + k + 1; N = T + 1;
    	for(int i = 1; i <= n; i++) {
    		int t; scanf("%d", &t);
    		ans += t;
    		addedge(S, i, t);
    	}
    	for(int i = 1; i <= n; i++) {
    		int t; scanf("%d", &t);
    		ans += t;
    		addedge(i, T, t);
    	}
    	while(m--) {
    		int u, v, w; scanf("%d%d%d", &u, &v, &w);
    		addedge(u, v, w); addedge(v, u, w);
    	}
    	for(int i = 1; i <= k; i++) {
    		int t, a, b; scanf("%d%d%d", &t, &a, &b);
    		ans += b;
    		if(a) {
    			while(t--) {
    				int h; scanf("%d", &h);
    				addedge(h, n + i, INF);
    			}
    			addedge(n + i, T, b);
    		} else {
    			while(t--) {
    				int h; scanf("%d", &h);
    				addedge(n + i, h, INF);
    			}
    			addedge(S, n + i, b);
    		}
    	}
    	printf("%d
    ", ans - maxFlow());
    	
    	return 0;
    }
    

      

    4177: Mike的农场

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 163  Solved: 111
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行三个整数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表示全为羊)。

    Output

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

    Sample Input

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

    Sample Output

    108

    HINT

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

    Source

  • 相关阅读:
    Linux查看密码
    zabbix 邮件报警配置
    Linux 修改zabbix server的web访问端口
    Zabbix 配置监控主机
    Linux 安装zabbix
    Json解析注解 ---@SerializedName
    IntelliJ IDEA 设置背景图片
    @Override is not allowed when implementing interface method
    nginx ------反向代理和负载均衡
    IntelliJ IDEA 性能优化
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4768558.html
Copyright © 2020-2023  润新知