hdu 4322 Candy(最大费用流)2012 Multi-University Training Contest 3

Candy

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 164    Accepted Submission(s): 39


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.
 

Source
 

Recommend
zhoujiaqi2010
 

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4322

题意:有n块糖,m个小孩,每个小孩有喜欢的糖,把他喜欢的糖给他则他获得K的 高兴值,普通糖则获得1个高兴值,求能否使得所有小孩的高兴值都大于所给值

分析:这题比赛时一开始以为是DP,优化了n久还是TLE,后来想到了网络流,构建了一个类似题解的模型,可惜我还是嫩了点。。。模型是最大流,然后剩下的特殊处理,导致错误。。。。

正解就是最大费用流,首先给每个小孩限制糖果数,用的就是最大流,也就是我一开始想到的,其次在最大流的基础上加上费用,并把每个小孩的剩余值另立一条边,然后求最大费用最大流,在这里我想喷一下数据,居然少了一组,居然还有人过了。。。我悲剧的读入矩阵时,用单个变量就悲剧了,如果用数组的话,就会保留前一组数据,答案就对了。。。悲剧啊~~~

不过这题算个好题吧

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int oo=1e9;
const int mm=8888;
const int mn=44;
int node,src,dest,edge,need,sum;
int ver[mm],cost[mm],flow[mm],next[mm];
int head[mn],dis[mn],q[mn],p[mn],b[22],a[22][22];
bool vis[mn];
void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0;i<node;++i)head[i]=-1;
    edge=0;
}
void addedge(int u,int v,int f,int c)
{
    ver[edge]=v,flow[edge]=f,cost[edge]=c,next[edge]=head[u],head[u]=edge++;
    ver[edge]=u,flow[edge]=0,cost[edge]=-c,next[edge]=head[v],head[v]=edge++;
}
bool spfa()
{
    int i,u,v,l,r=0,tmp;
    for(i=0;i<node;++i)dis[i]=oo;
    dis[q[r++]=src]=0;
    p[src]=p[dest]=-1;
    for(l=0;l!=r;++l>=mn?l=0:l)
        for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])
            if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i]))
            {
                dis[v]=tmp;
                p[v]=i^1;
                if(vis[v])continue;
                vis[q[r++]=v]=1;
                if(r>=mn)r=0;
            }
    return p[dest]>-1;
}
int SpfaFlow()
{
    int i,ret=0,delta;
    while(spfa())
    {
        for(i=p[dest],delta=oo;i>=0;i=p[ver[i]])
            if(flow[i^1]<delta)delta=flow[i^1];
        for(i=p[dest];i>=0;i=p[ver[i]])
            flow[i]+=delta,flow[i^1]-=delta;
        ret-=delta*dis[dest];
        sum+=delta;
    }
    return ret;
}
int main()
{
    int i,j,n,m,k,t,cs=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        prepare(n+m+2,0,n+m+1);
        for(i=1;i<=n;++i)
            addedge(src,i,1,0);
        sum=need=0;
        for(i=1;i<=m;++i)
        {
            scanf("%d",&b[i]);
            if(b[i]>=k)addedge(n+i,dest,b[i]/k,-k);
            if(b[i]%k>1)addedge(n+i,dest,1,-(b[i]%k));
            need+=b[i];
        }
        for(i=1;i<=m;++i)
            for(j=1;j<=n;++j)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j])addedge(j,n+i,1,0);
            }
        need-=SpfaFlow();
        printf("Case #%d: ",++cs);
        if(n-sum>=need)puts("YES");
        else puts("NO");
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值