hdu 4322 Candy 费用流

来源:互联网 发布:用友erpu8软件介绍 编辑:程序博客网 时间:2024/05/16 02:02
题解copy别人的。。

Candy
【题目大意】
有N颗糖果和M个小孩,老师现在要把这N颗糖分给这M个小孩。每个小孩i对每颗糖j都有一个偏爱度Aij,如果他喜欢这颗糖,Aij = k,否则Aij = 1。小孩i觉得高兴当且仅当ΣCij×Aij >= Bi,j=1,2,…,N,若他分得了糖j,Cij = 1,否则Cij = 0。问能否合理分配这N颗糖,使得每个小孩都觉得高兴。
【建模方法】
(最大费用最大流)
 本题有一个突破点就是:他喜欢这颗糖,Aij = k,否则Aij = 1,关键在于如果他不喜欢这个糖分给他一样可以获得1点的欢乐值。也就是说如果之前分配了的糖给了小孩一定的欢乐值,不够bi,可以直接用随意的糖去填满。
首先我们要求欢喜值>=bi,是否可以认为当我获得欢喜值为bi后,多余欢喜值对这个结果的满足是没有贡献的。也就是说,你可以用一个容量来控制分配糖对小孩欢喜值的控制,让获得欢喜值最多为bi。如果不够,最后用一些1的糖来填满。
而这个容量就是bi/c,获取贡献为k,bi%c(>1)的也是可以用一个能让这个小孩欢喜的糖来贡献,但是其费用只为bi%c。
对于小孩来说,最大费用最大流后,糖分配的贡献值为最大费用,剩余糖就是(n-最大流),然后用这些糖去填不满的,只要满足总和大于Σbj。就可以分配了。


具体建模方案1:
(s,i,1,0);
(i,j,1,0);
(j,t,bj/k,k);
If(bj%k>1)
(j,t,1,bj%k)
Ans = 费用 + N – 最大流 >= Σbj  则满足要求
具体建模方案2:
(s,I,1,0)
(I,j,1,0)
(j,t,bj/k,k-1);
If(bj%k>1)
(j,t,1,bj%k-1);
Ans = 费用+N  >= Σbj  则满足要求

#include <stdio.h>#include <iostream>#include <string.h>using namespace std;const int N=400;const int MAXE=20000000;const int inf=1<<30;int head[N],s,t,cnt,n,m,ans;int d[N],pre[N];bool vis[N];int q[MAXE];struct Edge{    int u,v,c,w,next;}edge[MAXE];void addedge(int u,int v,int w,int c){    edge[cnt].u=u;    edge[cnt].v=v;    edge[cnt].w=w;    edge[cnt].c=c;    edge[cnt].next=head[u];    head[u]=cnt++;    edge[cnt].v=u;    edge[cnt].u=v;    edge[cnt].w=-w;    edge[cnt].c=0;    edge[cnt].next=head[v];    head[v]=cnt++;}int SPFA(){    int l,r;    memset(pre,-1,sizeof(pre));    memset(vis,0,sizeof(vis));    for(int i=0;i<=t;i++) d[i]=inf;    d[s]=0;    l=0;r=0;    q[r++]=s;    vis[s]=1;    while(l<r)    {        int u=q[l++];        vis[u]=0;        for(int j=head[u];j!=-1;j=edge[j].next)        {            int v=edge[j].v;            if(edge[j].c>0&&d[u]+edge[j].w<d[v])            {                d[v]=d[u]+edge[j].w;                pre[v]=j;                if(!vis[v])                {                    vis[v]=1;                    q[r++]=v;                }            }        }    }    if(d[t]==inf)        return 0;    return 1;}int MCMF(){    int flow=0;    while(SPFA())    {        int u=t;        int mini=inf;        while(u!=s)        {            if(edge[pre[u]].c<mini)                mini=edge[pre[u]].c;                u=edge[pre[u]].u;        }        flow+=mini;        u=t;        ans+=d[t]*mini;        while(u!=s)        {            edge[pre[u]].c-=mini;            edge[pre[u]^1].c+=mini;            u=edge[pre[u]].u;        }    }    return flow;}int main(){    int T;    int i,j;    int like[20][20];    int B[20];    int k;    scanf("%d",&T);    int cas=0;    while(T--)    {        ans=0;        int sum=0;        cas++;        scanf("%d%d%d",&n,&m,&k);int i;        s=0;t=n+m+1;cnt=0;        for(i=0;i<=t;i++)            head[i]=-1;        for(i=1;i<=m;i++)        {            scanf("%d",&B[i]);            sum+=B[i];        }        for(i=1;i<=m;i++)            for(j=1;j<=n;j++)            {                scanf("%d",&like[i][j]);                if(like[i][j]==1)                    addedge(j,n+i,0,1);            }        for(i=1;i<=n;i++) addedge(s,i,0,1);        for(i=1;i<=m;i++)        {            if(B[i]%k>1)            {                addedge(i+n,t,-k,B[i]/k);                addedge(i+n,t,-B[i]%k,1);            }            else addedge(i+n,t,-k,B[i]/k);        }        int maxflow=MCMF();        //printf("%d ",ans);        if(-ans+n-maxflow>=sum)            printf("Case #%d: YES\n",cas);        else printf("Case #%d: NO\n",cas);    }    return 0;}


 

0 0
原创粉丝点击