Candy
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2381 Accepted Submission(s): 721
Problem Description
There are N candies and M kids, the teacher will give this N candies to the M kids. The i-th kids for the j-th candy has a preference for like[i][j], if he like the sugar, like[i][j] = 1, otherwise like[i][j] = 0. If the i-th kids get the candy which he like he will get K glad value. If he or she do not like it. He will get only one glad value. We know that the i-th kids will feel happy if he the sum of glad values is equal or greater than B[i]. Can you tell me whether reasonable allocate this N candies, make every kid feel happy.
Input
The Input consists of several cases .The first line contains a single integer t .the number of test cases.
For each case starts with a line containing three integers N, M, K (1<=N<=13, 1<=M<=13, 2<=K<=10)
The next line contains M numbers which is B[i](0<=B[i]<=1000). Separated by a single space.
Then there are M*N like[i][j] , if the i-th kids like the j-th sugar like[i][j]=1 ,or like[i][j]=0.
Output
If there have a reasonable allocate make every kid feel happy, output "YES", or "NO".
Sample Input
2
3 2 2
2 2
0 0 0
0 0 1
3 2 2
2 2
0 0 0
0 0 0
Sample Output
Case #1: YES
Case #2: NO
Hint
Give the first and second candy to the first kid. Give the third candy to the second kid. This allocate make all kids happy.
解析:
最大费用最大流。
偷懒挂个链接:Candy
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int Max=300;
int t,n,m,k,ans1,ans2,sum,size=1,S,T,head,tail;
int f[50][50],dis[Max],first[Max],tmp[Max],b[Max],p[Max],vis[Max],v[Max];
struct shu{int to,next,len,c;}; //c费用
shu edge[Max];
inline void clean()
{
size=1,sum=ans1=ans2=0;
memset(f,0,sizeof(f));
memset(first,0,sizeof(first));
memset(v,0,sizeof(v));
}
inline void build(int x,int y,int z,int c)
{
edge[++size].next=first[x],first[x]=size,edge[size].to=y,edge[size].len=z,edge[size].c=c;
edge[++size].next=first[y],first[y]=size,edge[size].to=x,edge[size].len=0,edge[size].c=-c;
}
inline void pre()
{
for(int i=1;i<=n;i++) build(S,i,1,0);
for(int i=1;i<=m;i++)
{
build(i+n,T,b[i]/k,-k);
if(b[i]%k>1) build(i+n,T,1,-b[i]%k);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(f[i][j]) build(j,i+n,1,0);
}
inline int spfa()
{
memset(dis,0x3f,sizeof(dis)),memset(vis,0,sizeof(vis));
head=0,tail=1;dis[S]=0;p[1]=S,vis[S]=1;
while(head<=tail)
{
int point=p[++head];
vis[point]=0;
for(int u=first[point];u;u=edge[u].next)
{
if(edge[u].len > 0 && dis[point]+edge[u].c < dis[edge[u].to])
{
dis[edge[u].to]=dis[point]+edge[u].c;
if(!vis[edge[u].to])
{
vis[edge[u].to]=1;
p[++tail]=edge[u].to;
}
}
}
}
if(dis[T] == dis[100]) return 0;
else return 1;
}
inline int dinic(int point,int flow)
{
if(point == T) return flow;
v[point]=1;
int sum=0;
for(int &u=tmp[point];u;u=edge[u].next)
if(!v[edge[u].to] && dis[edge[u].to] == dis[point] + edge[u].c && edge[u].len > 0)
{
int minn=dinic(edge[u].to,min(flow-sum,edge[u].len));
ans2+=minn*edge[u].c;
edge[u].len-=minn;
edge[u^1].len+=minn;
sum+=minn;
if(flow-sum == 0) break;
}
v[point]=0;
return sum;
}
inline void solve()
{
while(spfa())
{
memcpy(tmp,first,sizeof(first));
ans1+=dinic(S,inf);
}
}
int main()
{
scanf("%d",&t);
for(int q=1;q<=t;q++)
{
printf("Case #%d: ",q);
clean();
scanf("%d%d%d",&n,&m,&k);T=30;
for(int i=1;i<=m;i++) scanf("%d",&b[i]),sum+=b[i];
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++) scanf("%d",&f[i][j]);
pre();
solve();
if(sum+ans2<=n-ans1) printf("YES\n");
else printf("NO\n");
}
return 0;
}