/* 返回顶部 */

POJ1149 PIGS

gate

用时:debug时间90分钟。

先读m再读n

我是傻逼(1/1)

题目大意:
\(m\)个房子,\(n\)个顾客。第\(i\)个房子里有\(a_i\)只猪;第\(i\)个顾客可以买至多\(b_i\)只猪,且可以打开房子\(c_1,c_2,...c_j\),这些同时被打开的房子中,剩余的猪的可以互相转移。求最多卖出的猪数量。

很难想到是网络流,知道是网络流也很难建图。
网络流建模汇总 - Edelweiss里有对这道题很详细的解释。

  • 首先设置超级源点\(S\)和超级汇点\(T\)

设当前顾客为\(i\),打开的一个房子为\(x\),起始时猪的数量为\(a_x\)

  • 顾客\(i\)\(T\)连边,权值为\(i\)的购买上限;
  • 如果\(x\)第一次被打开,\(S\)\(i\)连边,权值为\(a_x\)
  • 如果\(x\)不是第一次被打开,上一个打开\(x\)的顾客\(last[x]\)\(i\)连边,权值为\(INF\)
    即,\(last[x]\)购买后剩余的猪的数量都可以转移给\(i\)

\(code\)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#define MogeKo qwq
using namespace std;

const int maxn = 2e5+10;
const int INF  = 0x3f3f3f3f;

int n,m,k,s,t,cnt,ans;
int head[maxn],to[maxn],nxt[maxn],w[maxn];
int cur[maxn],dis[maxn],last[maxn],a[maxn];

void add(int x,int y,int z) {
	to[++cnt] = y;
	nxt[cnt] = head[x];
	head[x] = cnt;
	w[cnt] = z;
}

void addedge(int x,int y,int z) {
	add(x,y,z);
	add(y,x,0);
}

bool bfs(){
	memset(dis,0,sizeof(dis));
    queue <int> q;
    dis[s] = 1;
    q.push(s);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if(!dis[v] && w[i]) {
                dis[v] = dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[t];
}

int dfs(int u,int flow) {
	if(u == t) return flow;
	int sum = 0;
	for(int &i = cur[u]; i; i = nxt[i]) {
		int v = to[i];
		if(dis[v] == dis[u]+1 && w[i]) {
			int ff = dfs(v,min(flow,w[i]));
			flow -= ff;
			sum += ff;
			w[i] -= ff;
			w[i^1] += ff;
			if(!flow) break;
		}
	}
	if(!sum) dis[u] = -1;
	return sum;
}

void dinic() {
	while(bfs()) {
		for(int i = 0; i <= n+1; i++)
			cur[i] = head[i];
		ans += dfs(s,INF);
	}
}

int main() {
	scanf("%d%d",&m,&n);
	for(int i = 1; i <= m; i++)
		scanf("%d",&a[i]);
	s = 0,t = n+1,cnt = 1;
	for(int i = 1; i <= n; i++) {
		int x,y = 0;
		scanf("%d",&k);
		while(k--) {
			scanf("%d",&x);
			if(!last[x]) y += a[x];
			else addedge(last[x],i,INF);
			last[x] = i;
		}
		addedge(s,i,y);
		scanf("%d",&y);
		addedge(i,t,y);
	}
	dinic();
	printf("%d",ans);
	return 0;
}
posted @ 2020-07-08 11:46  Mogeko  阅读(67)  评论(0编辑  收藏  举报