POIJ 1149 PIGS 最大流 建图是关键

题意:某猪场由M个猪圈,N个顾客来买猪,每个猪圈有一定数量的猪,每个顾客有一个卖猪数量的最大值,每个顾客有某些猪圈的钥匙,打开相应猪圈后顾客挑选猪,在猪圈关闭前,打开门的这些猪可以任意分配到当前打开门的猪圈,买完关闭猪圈。下一个顾客重复以上操作。


将每个顾客当做一个节点来表示,再加入超级源点和超级汇点。

1. 对于每个猪圈的第一个顾客,从源点向他连一条边,容量为猪圈里的猪的数量。

2. 对于每个猪圈,如果不是第一个顾客,则上一个打开这个猪圈的顾客向这个顾客连一条边,容量为 +∞。

3. 每个顾客到汇点连一条边,容量为各个顾客能买的最大数量。

 #include<cstdio>
 #include<cstring>
 #include<queue>
 #include<cmath>
 using namespace std;
 #define INF 0x3f3f3f3f
 const int Ni = 210;
 const int MAX = 1<<26;
 struct Edge{
     int u,v,c;
     int next;
 }edge[20*Ni];
 int n,m;
 int edn;//边数
 int p[Ni];//父亲
 int d[Ni];
 int sp,tp;//源点,汇点
 int pig[1010],pre[1010];

 void addedge(int u,int v,int c)
 {
     edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
     edge[edn].next=p[u]; p[u]=edn++;

     edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
     edge[edn].next=p[v]; p[v]=edn++;
 }
 int bfs()
 {
     queue <int> q;
     memset(d,-1,sizeof(d));
     d[sp]=0;
     q.push(sp);
     while(!q.empty())
     {
         int cur=q.front();
         q.pop();
         for(int i=p[cur];i!=-1;i=edge[i].next)
         {
             int u=edge[i].v;
             if(d[u]==-1 && edge[i].c>0)
             {
                 d[u]=d[cur]+1;
                 q.push(u);
             }
         }
     }
     return d[tp] != -1;
 }
 int dfs(int a,int b)
 {
     int r=0;
     if(a==tp)return b;
     for(int i=p[a];i!=-1 && r<b;i=edge[i].next)
     {
         int u=edge[i].v;
         if(edge[i].c>0 && d[u]==d[a]+1)
         {
             int x=min(edge[i].c,b-r);
             x=dfs(u,x);
             r+=x;
             edge[i].c-=x;
             edge[i^1].c+=x;
         }
     }
     if(!r)d[a]=-2;
     return r;
 }

 int dinic(int sp,int tp)
 {
     int total=0,t;
     while(bfs())
     {
         while(t=dfs(sp,MAX))
         total+=t;
     }
     return total;
 }
 int main()
 {
     int i,j,u,v,cap,a,b;
     while(~scanf("%d%d",&m,&n))
     {
         edn=0;//初始化
         memset(p,-1,sizeof(p));
         memset(pre,0,sizeof pre);
         sp=0;tp=n+1;
         for(i=1;i<=m;i++) scanf("%d",&pig[i]);
         for(i=1;i<=n;i++)
         {
             scanf("%d",&a);
             while(a--)
			 {
			 	scanf("%d",&j);
			 	if(!pre[j]) addedge(0,i,pig[j]);
			 	else addedge(pre[j],i,INF);
				pre[j]=i;
			 }
			 scanf("%d",&b);
			 addedge(i,n+1,b);
         }
         printf("%d\n",dinic(sp,tp));
     }
     return 0;
 }



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值