JOJ 2453 Candy

【JOJ 2453】Candy

Description

有N 颗糖果和M 个小孩,老师现在要把这N 颗糖分给这M 个小孩。每个小孩i对每颗糖j 都有一个偏爱度Aij,如果他喜欢这颗糖,Aij = 2,否则 Aij = 1。小孩 i觉得高兴当且仅当∑Cij×Aij >= Bi,j=1,2, …,N ,若他分得了糖 j ,Cij = 1,否则 Cij = 0。问能否合理分配这 N 颗糖,使得每个小孩都觉得高兴。(1 <= N <= 100,000, 1 <= M <= 10, 0 <= Bi <= 1,000,000,000)

Input

多组数据
首先T,表示数据组数。
每组数据里面,第一行n,m
然后n行每行m个
表示第i个糖果对于第j个小朋友的价值
最后m行,表示b[];

Output

"Yes" OR "No",每组数据换行输出;

Sample Input

5
10 5
2 2 1 2 1 
2 1 2 1 2 
1 2 2 2 1 
2 1 2 1 1 
1 2 1 1 1 
1 1 2 2 2 
1 1 1 2 2 
1 1 1 2 2 
2 1 1 1 1 
1 1 2 1 2 
1 1 2 1 2 
10 5
2 2 2 2 1 
2 1 1 1 2 
2 1 1 2 1 
2 1 2 1 2 
1 2 1 2 1 
2 1 2 2 1 
1 2 1 1 2 
1 2 2 1 1 
2 2 1 2 1 
1 2 2 1 1 
3 2 2 3 3 
10 5
1 1 2 1 1 
1 2 2 1 2 
2 2 2 1 2 
1 1 1 2 1 
1 2 2 1 1 
1 1 1 2 1 
1 1 2 1 1 
1 1 2 1 2 
2 2 1 1 1 
1 1 1 1 1 
3 2 3 2 2 
10 5
1 1 1 2 1 
1 1 1 1 1 
1 1 2 2 1 
2 1 2 1 1 
1 1 1 1 1 
2 2 2 2 2 
1 2 2 2 1 
2 1 2 2 1 
2 1 1 2 2 
1 1 1 1 2 
1 3 2 3 3 
10 5
2 1 2 2 2 
1 1 1 2 2 
2 1 1 1 2 
2 2 1 1 1 
2 2 2 1 2 
1 1 1 1 1 
2 2 1 2 1 
2 2 1 1 2 
1 2 1 1 2 
2 1 2 2 2 
1 2 3 3 3 

Sample Output

Yes
Yes
Yes
Yes
Yes

Solution

我们的网络流之中,流量并不能根据前方需要的流量而给出相应的价值。
也就是说,一颗糖果既有可能价值为1又有可能价值为2的情况在最大流中
是不存在的。
但是我们唯一可以判别的就是价值为0和价值为1的两种情况了。因为我们
将每一颗糖果的价值定为1那么我们就可以通过不选取这颗糖果的方式使其
价值变为0。
我们再限制每一个孩子能够得到的糖果的个数为自己所需的上限,因为多得
到的糖果实际上对此题毫无意义,是属于浪费的行为。
我们将糖果价值变为0或1之后的最大流其实是每一个孩子得到的2价糖果总
数,所以孩子的流量限制为所需个数的一半。
这时候我们将最大流与糖果总数相加,如果能够满足总的需求,那么就一定
存在一种符合要求的分配方案。
但是我们还会发现糖果总数非常的大,刚才我们讲述的建图方式一定会超时。
因为我们可以把去向完全相同的点合并成为一个点,加上最多只有十个孩子,
那么最多存在2^10种糖,就大大减少了糖的个数 。
将一颗糖转化为二进制数,2代表1,1代表0。从源点向每一种糖连边,价值为
重复次数,将其取出后按位连边。 
建图:
st--> i,flow=mark[i]
i--> kid,flow=mark[i]
kid--> ed,flow=floor(sum[kid]/2)

CODE

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
inline int read(){
	char c;int rec=0;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
	return rec;
}
struct Hose {int next,to,flow;}hose[50005];
int h[2005],cnt;
inline void add(int x,int y,int z){
	hose[++cnt].to=y;hose[cnt].next=h[x];h[x]=cnt;hose[cnt].flow=z;
	hose[++cnt].to=x;hose[cnt].next=h[y];h[y]=cnt;hose[cnt].flow=0;
	return ;
}
int mark[2005];
int n,m,T,N,x,ans,sum=0;
int st,ed;
int Gap[2005],dis[2005];
inline int SAP(int v,int maxflow){
	if(v==ed)return maxflow;
	int temp=maxflow,i,j,p;
	for(i=h[v];i;i=hose[i].next){
		j=hose[i].to;
		if(hose[i].flow&&dis[v]==dis[j]+1){
			p=SAP(j,min(temp,hose[i].flow));
			temp-=p;hose[i].flow-=p;hose[i^1].flow+=p;
			if(temp==0||dis[st]==N)return maxflow-temp;
		}
	}
	if(--Gap[dis[v]]==0)dis[st]=N;
	else Gap[++dis[v]]++;
	return maxflow-temp;
}
inline void Clean(){
	memset(h,0,sizeof(h));memset(mark,0,sizeof(mark));
	memset(Gap,0,sizeof(Gap));memset(dis,0,sizeof(dis));
	ans=0;cnt=1;sum=0;return ;
}
int main(){
	T=read();
	while(T--){
		Clean();
		n=read();m=read();st=0;ed=2005;N=n+m+2;
		for(int i=1;i<=n;i++){
			int a=0;
			for(int j=1;j<=m;j++){
				x=read();
				a=a<<1|(x==2);
			}mark[a]++;
		}
		for(int i=1;i<=1024;i++){
			if(mark[i]){
				add(st,i+m,mark[i]);
				for(int j=1;j<=m;j++)
					if(i>>(j-1)&1)add(i+m,j,mark[i]);//非常尴尬。。。前面的i一直被写成了mark[i]... 
			}
		}
		for(int i=1;i<=m;i++){
			x=read();add(i,ed,x>>1);
			sum+=x;
		}
		Gap[0]=N;
		while(dis[st]<N)ans+=SAP(st,inf);
		if(sum<=n+ans)cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值