【USACO】New Years Party

时间:2020-08-05 14:28:24   收藏:0   阅读:79

题意描述

New Years Party

\(N(3\leq N\leq 200)\) 头奶牛举办新年聚会。每头奶牛会做几种不同的佳肴(以“碟”记数)。

一共有 \(D(5\leq D\leq 100)\) 种菜肴,依次以 \(1\)\(D\) 的数字标记。

大家希望聚会上的菜肴数量越多越好,但是同种菜肴的数量有一个上限。

每头奶牛可以带 \(K\) 碟菜肴 \((1\leq K\leq 5)\) ,但必须都是不同的菜肴。

求聚会上最多可能有多少碟菜肴?

算法分析

闲话

一开始以为是什么神仙 贪心 或 DP,结果撑死推不出 DP 柿子,又口胡不了贪心...。

经 dalao 点拨之后发现网络流模型是真的难看出来。

建图

建立一个超级源点连接 \(1\)~\(n\) 号节点(表示 \(1\)~\(n\) 号奶牛),边权为 \(k\)

\(i\) 号奶牛会做 \(j\) 号菜,就连接 \(edge(i,j+n)\),边权为 \(1\)

建立一个超级汇点连接 \(1+n\)~\(d+n\) 号节点(表示 \(1\)~\(d\) 号菜),边权为每种菜的数量上限。

网络流

然后就是 Dinic 的板子了(据说 EK 会 T)。

代码实现

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 210
#define D 110
#define M 5000010
#define INF 0x3f3f3f3f
using namespace std;

int n,kk,dd,s,t,head[N+D],cnt=1;
struct Edge{
	int nxt,to,val;
}ed[M];
queue<int>q;

int read(){
	int x=0,f=1;char c=getchar();
	while(c<‘0‘ || c>‘9‘) f=(c==‘-‘)?-1:1,c=getchar();
	while(c>=‘0‘ && c<=‘9‘) x=x*10+c-48,c=getchar();
	return x*f;
}

void add(int u,int v,int w){
	ed[++cnt].nxt=head[u];
	ed[cnt].to=v;
	ed[cnt].val=w;
	head[u]=cnt;
	ed[++cnt].nxt=head[v];
	ed[cnt].to=u;
	ed[cnt].val=0;
	head[v]=cnt;
	return;
}

int d[N+D]; 

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

int dinic(int u,int flow){
	if(u==t) return flow;
	int rest=flow;
	for(int i=head[u];i && rest;i=ed[i].nxt){
		int v=ed[i].to,w=ed[i].val;
		if(w && d[v]==d[u]+1){
			int k=dinic(v,min(rest,w));
			if(!k) d[v]=0;
			ed[i].val-=k;
			ed[i^1].val+=k;
			rest-=k;
		}
	}
	return flow-rest;
}

int main(){
	//freopen("party.in","r",stdin);
	//freopen("party.out","w",stdout);
	n=read(),kk=read(),dd=read();
	s=0,t=n+dd+1;
	int a,b;
	for(int i=1;i<=dd;i++)
		a=read(),add(i+n,t,a);
	for(int i=1;i<=n;i++){
		a=read();
		for(int j=1;j<=a;j++)
			b=read(),add(i,b+n,1);
	}
	for(int i=1;i<=n;i++) add(s,i,kk);
	int ans=0,flow;
	while(bfs())
		if(flow=dinic(s,INF)) ans+=flow;
	printf("%d\n",ans);
	//fclose(stdin);fclose(stdout);
	return 0;
}

完结撒花。

原文:https://www.cnblogs.com/lpf-666/p/13439389.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!