zoukankan      html  css  js  c++  java
  • [BZOJ1280][POJ1149]Emmy卖猪pigs

    [BZOJ1280][POJ1149]Emmy卖猪pigs

    试题描述

    Emmy在一个养猪场工作。这个养猪场有 (M) 个锁着的猪圈,但Emmy并没有钥匙。顾客会到养猪场来买猪,一个接着一个。每一位顾客都会有一些猪圈的钥匙,他们会将这些猪圈打开并买走固定数目的猪。 所有顾客有的钥匙和他们需要买猪的数量在事先都告诉了Emmy,于是Emmy要订一个计划,使得卖出去的猪最多。 买卖的过程是这样的:一个顾客前来,并打开所有他可以打开的猪圈。然后Emmy从这些猪圈里牵出固定数目的猪卖给顾客(最多只能和顾客需要数相等),并可以重新安排这些开着的猪圈中的猪。 每个猪圈可以存放任意数目的猪。 写一个程序,使得Emmy能够卖出去尽可能多的猪。

    输入

    第一行有两个整数:(M)(N),表示猪圈数和顾客数。 第二行有 (M) 个整数,表示每个猪圈初始时有多少猪。 接下来的 (N) 行按照前来的次序描述了每一个顾客,每行的格式如下:(A K_1 K_2 cdots K_A B) (A) 表示该顾客拥有的钥匙数,(K_1 cdots K_A) 表示每个钥匙所对应的猪圈,(B) 表示该顾客需要购买的猪的数目。

    输出

    仅包含一个整数,即最多能卖出去的猪的数目。

    输入示例

    3 3
    3 1 10
    2 1 2 2
    2 1 3 3
    1 2 6
    

    输出示例

    7
    

    数据规模及约定

    (1 le M le 1000)

    (1 le N le 100)

    题解

    首先源点向每个猪圈连一条容量为该猪圈内猪数目的边,然后每位客户向汇点连一条容量为该客户需要数的边。这是显然的。

    那么根据“可以打乱”这个性质,我们可以直接在客户和客户之间连边,而不是把边连回猪圈。

    这样,正解就产生了(以下边容量均为无穷):从猪圈向第一个有它钥匙的客户连边,然后有交集的客户之间连上边。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1111
    #define maxm 24010
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow;
    	Edge() {}
    	Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
    };
    struct Dinic {
    	int n, m, s, t, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	int vis[maxn], Q[maxn], hd, tl;
    	int cur[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c) {
    		es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		memset(vis, 0, sizeof(vis));
    		vis[t] = 1;
    		hd = tl = 0; Q[++tl] = t;
    		while(hd < tl) {
    			int u = Q[++hd];
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(!vis[e.from] && e.flow) {
    					vis[e.from] = vis[u] + 1;
    					Q[++tl] = e.from;
    				}
    			}
    		}
    		return vis[s] > 0;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return a;
    		int flow = 0, f;
    		for(int& i = cur[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0;
    		while(BFS()) {
    			rep(i, 1, n) cur[i] = head[i];
    			flow += DFS(s, oo);
    		}
    		return flow;
    	}
    } sol;
    
    #define maxpig 1010
    #define maxcus 110
    int n, p, A[maxpig];
    vector <int> customer[maxpig];
    bool G[maxcus][maxcus];
    
    int main() {
    	n = read(); p = read(); int S = n + p + 1, T = n + p + 2;
    	sol.init(); sol.setn(T);
    	rep(i, 1, n) sol.AddEdge(S, i, read());
    	rep(i, 1, p) {
    		int k = read();
    		while(k--) customer[read()].push_back(i);
    		sol.AddEdge(i + n, T, read());
    	}
    	
    	rep(i, 1, n) if(customer[i].size()) {
    		sol.AddEdge(i, customer[i][0] + n, oo);
    		rep(j, 1, (int)customer[i].size() - 1) {
    			int a = customer[i][j-1], b = customer[i][j];
    			if(!G[a][b]) sol.AddEdge(a + n, b + n, oo), G[a][b] = 1;
    		}
    	}
    	
    	printf("%d
    ", sol.MaxFlow(S, T));
    	
    	return 0;
    }
    
  • 相关阅读:
    内置函数
    递归函数:
    函数(迭代器与生成器)
    函数的装饰器
    函数:(函数的名字,闭包)
    函数(命名空间,作用域,嵌套)
    函数:(定义,调用,返回值和参数)
    hdu 4267 A Simple Problem with Integers(线段树)
    hdu 2089 不要62 hdu 3555 Bomb (数位DP)
    poj 2955 Brackets (区间DP)
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7906282.html
Copyright © 2011-2022 走看看