hdu 4322(最大费用最大流)

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

思路:建图真的是太巧妙了!直接copy大牛的了:

由于只要得到糖就肯定有1个快乐度,在这一点上糖的效果是等效的。所以只要考虑有特殊效果的糖的分配就可以了。

当快乐的程度超过b[i]时,多出来的部分就浪费了,为了使浪费尽可能少,我们用费用流加以控制,当获得最大费用最大流的时候,这是的费用的利用率就是最高的。在建图时只需考虑特殊的糖就可以了,建图方法:

原点到每个糖:流为1,费用为0。如果糖对某个人有特殊效果,连边:流为1,费用为0。人向汇点连边:最终快乐的程度不超过b[i]的情况:流为b[i]/k,限制这样的糖的数量,费用为k,因为特殊效果全部利用上了。快乐程度超过b[i]的情况:流为1,限制流量不超过b[i],费用为b[i] % k,因为多出来的快乐无效。当b[i] % k == 0时,这样的边没有必要。当b[i] % k == 1时,这时的糖和普通的糖无异,没必要连边。

最终算出来的费用就是特殊的糖被充分利用后已经分配的快乐程度,最大流为为了达到这样的程度使用的糖的数量,这样就还剩N - 最大流数量的糖被我们当做普通的糖使用,只要剩下的普通的糖的数目大于还需填充的快乐程度,就可以满足条件。

  1 #include<iostream>

  2 #include<cstdio>

  3 #include<cstring>

  4 #include<algorithm>

  5 #include<queue>

  6 using namespace std;

  7 #define MAXN 55

  8 #define MAXM 4444

  9 #define inf 1<<30

 10 

 11 struct Edge{

 12     int v,cap,cost,next;

 13 }edge[MAXM];

 14 

 15 int vs,vt,n,m,NE,sum,k;

 16 int head[MAXN];

 17 

 18 void Insert(int u,int v,int cap,int cost)

 19 {

 20     edge[NE].v=v;

 21     edge[NE].cap=cap;

 22     edge[NE].cost=cost;

 23     edge[NE].next=head[u];

 24     head[u]=NE++;

 25 

 26     edge[NE].v=u;

 27     edge[NE].cap=0;

 28     edge[NE].cost=-cost;

 29     edge[NE].next=head[v];

 30     head[v]=NE++;

 31 }

 32 

 33 int dist[MAXN],pre[MAXN],cur[MAXN];

 34 bool mark[MAXN];

 35 bool spfa(int vs,int vt)

 36 {

 37     memset(mark,false,sizeof(mark));

 38     fill(dist,dist+MAXN-1,-inf);

 39     dist[vs]=0;

 40     queue<int>que;

 41     que.push(vs);

 42     while(!que.empty()){

 43         int u=que.front();

 44         que.pop();

 45         mark[u]=false;

 46         for(int i=head[u];i!=-1;i=edge[i].next){

 47             int v=edge[i].v,cost=edge[i].cost;

 48             if(edge[i].cap>0&&dist[u]+cost>dist[v]){

 49                 dist[v]=dist[u]+cost;

 50                 pre[v]=u;

 51                 cur[v]=i;

 52                 if(!mark[v]){

 53                     mark[v]=true;

 54                     que.push(v);

 55                 }

 56             }

 57         }

 58     }

 59     return dist[vt]!=-inf;

 60 }

 61 

 62 int MinCostFlow(int vs,int vt)

 63 {

 64     int flow=0,cost=0;

 65     while(spfa(vs,vt)){

 66         int aug=inf;

 67         for(int u=vt;u!=vs;u=pre[u]){

 68             aug=min(aug,edge[cur[u]].cap);

 69         }

 70         flow+=aug,cost+=dist[vt]*aug;

 71         for(int u=vt;u!=vs;u=pre[u]){

 72             edge[cur[u]].cap-=aug;

 73             edge[cur[u]^1].cap+=aug;

 74         }

 75     }

 76     return n-flow>=sum-cost;

 77 }

 78 

 79 int like[MAXN][MAXN];

 80 int B[MAXN];

 81 int main()

 82 {

 83   //  freopen("1.txt","r",stdin);

 84     int _case,t=1;

 85     scanf("%d",&_case);

 86     while(_case--){

 87         scanf("%d%d%d",&n,&m,&k);

 88         NE=0,vs=0,vt=n+m+1,sum=0;

 89         memset(head,-1,sizeof(head));

 90         for(int i=1;i<=m;i++){

 91             scanf("%d",&B[i]);

 92             sum+=B[i];

 93         }

 94         for(int i=1;i<=n;i++)Insert(vs,i,1,0);

 95         for(int i=1;i<=m;i++){

 96             for(int j=1;j<=n;j++){

 97                 scanf("%d",&like[i][j]);

 98                 if(like[i][j]==1)Insert(j,i+n,1,0);

 99             }

100             Insert(i+n,vt,B[i]/k,k);

101             if(B[i]%k>1){

102                 Insert(i+n,vt,1,B[i]%k);

103             }

104         }

105         printf("Case #%d: ",t++);

106         if(MinCostFlow(vs,vt)){

107             puts("YES");

108         }else

109             puts("NO");

110     }

111     return 0;

112 }
View Code

 

你可能感兴趣的:(HDU)