hdu 4322 Candy 费用流

题解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
",cas);
        else printf("Case #%d: NO
",cas);
    }
    return 0;
}


 

原文地址:https://www.cnblogs.com/vermouth/p/3710139.html