hdu 4322 (费用流,巧妙建图)

题意:如果一个小孩得到他喜欢的一种糖果他会得到k个欢乐值,如果得到不喜欢的糖果只能得到1个欢乐值,每个孩子只有当欢乐值达到一定数量时才会高兴。能不能使所有的孩子都高兴。

分析:如果一种糖果没人喜欢的话,不管把它给谁效果都是一样的,所以只需要把有人喜欢的糖果分给孩子,得到一个最大的欢乐值,然后再用普通糖果去给那些没有达到限制的欢乐值。这里应该注意的是:这样求出的特殊糖果带来的最大欢乐值代表,所有孩子总的欢乐值,不能代表每个孩子有多少欢乐值,无法判断多少个孩子没有满足。所以我们要控制每个孩子得到的欢乐值最大就是刚好满足的欢乐值就可以了。






#include<stdio.h>
#include<queue>
#include<string.h>
const int N=50;
const int inf=0x3fffffff;
using namespace std;
int dist[N],pre[N],vis[N],head[N],num,start,end,B[N],n,m,k,cnt,like[N][N];
struct edge
{
	int st,ed,cost,flow,next;
}e[N*N];
void addedge(int x,int y,int c,int w)
{
	e[num].st=x;e[num].ed=y;e[num].cost=c; e[num].flow=w;e[num].next=head[x];head[x]=num++;
	e[num].st=y;e[num].ed=x;e[num].cost=-c;e[num].flow=0;e[num].next=head[y];head[y]=num++;
}
int SPFA()
{
	queue<int>Q;
	int i,v,u;
	for(i=0;i<=end;i++)
	{dist[i]=-inf;vis[i]=0;pre[i]=-1;}
	dist[start]=0;vis[start]=1;
	Q.push(start);
	while(!Q.empty())
	{
		u=Q.front();Q.pop();
		vis[u]=0;
		for(i=head[u];i!=-1;i=e[i].next)
		{
			v=e[i].ed;
			if(e[i].flow>0&&dist[v]<dist[u]+e[i].cost)
			{
				dist[v]=dist[u]+e[i].cost;
				pre[v]=i;
				if(vis[v]==0)
				{
					Q.push(v);
					vis[v]=1;
				}
			}
		}
	}
	if(pre[end]==-1)
		return 0;
	return 1;
}
int Mincost()
{
	int i,maxflow=0,minflow,maxcost=0;
	while(SPFA())
	{
		minflow=inf;
		for(i=pre[end];i!=-1;i=pre[e[i].st])
			if(minflow>e[i].flow)
				minflow=e[i].flow;
			maxflow+=minflow;
		for(i=pre[end];i!=-1;i=pre[e[i].st])
		{
			e[i].flow-=minflow;
			e[i^1].flow+=minflow;			 
		}
	   maxcost+=dist[end];
	}
	if(m-maxflow>=cnt-maxcost)return 1;
	return -1;
}
int main()
{
	int i,j,x,t,sum,op=1;
	scanf("%d",&t);
	while(t--)
	{
		memset(head,-1,sizeof(head));
		num=0;cnt=0;
		scanf("%d%d%d",&m,&n,&k);
		start=0;end=n+m+1;
		for(i=1;i<=n;i++)
		{scanf("%d",&B[i]);cnt+=B[i];}
		for(i=1;i<=n;i++)
		{
			
			for(j=1;j<=m;j++)
			{
				scanf("%d",&like[i][j]);
				if(like[i][j]==1)
					addedge(j+n,i,0,1);//糖果向孩子建边
			}
			x=B[i]/k;
			addedge(i,end,k,x);//x个糖果,每个糖果带来k个欢乐值
			if(B[i]%k>1)//如果等于1的话用普通糖果
				addedge(i,end,B[i]%k,1);//1个糖果带来B[i]%k个欢乐值,保证得到的欢乐值最大等于B[i];
		}
		for(i=1;i<=m;i++)
			addedge(start,i+n,0,1);
		sum=Mincost();
		printf("Case #%d: ",op++);
		if(sum==-1)printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}


你可能感兴趣的:(编程,算法,百度,ACM,网络流)