【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[];
首先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
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
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)
也就是说,一颗糖果既有可能价值为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;
}