poj 1149 (一时不明显的建图+最大流)

本文介绍了一个基于最大流算法解决的养猪场买卖问题。通过构建特殊网络流模型,模拟顾客依次购买猪的过程,实现迈克养猪场的最大收益。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:
迈克有个养猪场,养猪场里有M个猪圈,每个猪圈都上了锁。迈克没有钥匙,而要买猪的顾客一个接一个来到养猪场,
每个顾客有一些猪圈的钥匙,要买一定数量的猪。当每个顾客来时,将有钥匙的猪圈全部打开,从中挑出一些买走,
然后迈克可以重新分配这些猪圈里面的猪。当顾客离开后,门又被锁上。问迈克最多可以卖多少猪。
分析 :
(1)将顾客看做是除了源点和汇点以外的结点,并且另外设两个结点:源点和汇点。 
(2)源点和每个猪圈的第1个顾客连边,边的权是开始时猪圈中猪的数量。 
(3)若源点和每个结点之间有重边,可以合并。 
(4)顾客j紧跟顾客i之后打开猪圈,则边的权是正无穷大,因为如果j紧跟i之后打开,迈克可以根据j的需求将其他猪圈调到该猪圈,
     这样顾客j就可以买到尽可能多的猪。已开启的数目可以随意变动,如果打开过则与上一个打开的顾客连一条正无穷的边,
 (5)每个顾客和汇点之间连边,表示顾客希望买猪的数目。 


#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=500;
const int M=10000;
const int inf=1<<30 ;
struct node
{
	int u,v,c,next;
}edge[M];
int pre[N],cur[N],gap[N],dis[N],head[N];
int has[M],pig[M];
int top ;
 
 void add(int u, int v ,int c)
 {
 	  edge[top].u=u;
 	  edge[top].v=v;
 	  edge[top].c=c;
 	  edge[top].next=head[u];
 	  head[u]=top++;
 	  edge[top].u=v;
 	  edge[top].v=u;
 	  edge[top].c=0;
 	  edge[top].next=head[v];
 	  head[v]=top++;
 }
 
 int sap(int s,int t,int nv)
{
    
    int flow=0,max_flow=inf,u,v;
    memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
    for(int i=0; i<nv; i++)          cur[i]=head[i];         
    gap[s]=nv;
    u=pre[s]=s;
    while(dis[s]<nv)
    {
        
        loop :
        for(int &j=cur[u]; j!=-1; j=edge[j].next)
        {
             v=edge[j].v;
            if(edge[j].c>0&&dis[u]==dis[v]+1)
            {
                
                if(edge[j].c<max_flow) max_flow=edge[j].c;
                pre[v]=u;
                u=v;
                if(v==t)     
				{
					for(u=pre[v];v!=s;v=u,u=pre[u])
					{
						edge[cur[u]].c-=max_flow;
						edge[cur[u]^1].c+=max_flow;
					}
					flow+=max_flow;
				    max_flow=inf;
				}              
               goto loop ;
            }
        }
        int mindis=nv;
        for(int j=head[u]; j!=-1; j=edge[j].next)
        {
             v=edge[j].v;
            if(edge[j].c>0&&dis[v]<mindis)
            {
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)
            break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}

 int main()
 {
 	int m,n,A,sum,k,B;
 	while(~scanf("%d%d",&m,&n))
 	{
			int s=0,t=n+1;
			top=0;
 		    memset(head,-1,sizeof(head));
 		    memset(has,0,sizeof(has));
 		    for(int i = 1 ; i <= m ; i++)
 		      scanf("%d",&pig[i]);
 		    for(int i = 1 ; i <= n ; i++)
 		    {
 		    	   sum=0;
				   scanf("%d",&A);
				   while(A--)
				   {     
				   	     scanf("%d",&k);
				         if(!has[k]) sum+=pig[k];  
				   	     else add(has[k],i,inf); //i紧跟上一个顾客选,连无穷边。 
				   	     has[k]=i;  //更新,k猪圈正被i顾客选。 
				   }	 
 		    	   add(s,i,sum);   //i顾客有sum可以选;sum<B时,还可以从它上一个顾客与它连的边提供。 
 		    	   scanf("%d",&B); //i顾客只选B只。 
				   add(i,t,B); 
 		    }
 		    int ans=sap(s,t,t+1);
 		    printf("%d\n",ans);
 	}
 	  return 0;
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值