poj1149 PIGS 网络最大流Dinic

题意:mike在养猪场工作,里面有M个猪圈,每个猪圈都上了锁。mike没有钥匙所以不能打开任何一个猪圈。要买猪的顾客一个接一个来到养猪场,每个顾客有一个猪圈的钥匙,而且他们要买一定数量的猪。有些信息mike是要知道的:顾客所拥有的钥匙,要购买的数量。求mike一天卖出去的最大数量。

比如:3 3

3 1 10 

2 1 2 2

2 1 3 3

1 2 6

表示3个猪圈,3个顾客。第二行表示各个猪圈的数量。第三行到后面,第一个数2表示这个顾客拥有的钥匙数量。1,2表示第1个猪圈,第2个猪圈的钥匙。最后一个2表示要购买的猪的数量。

解题:这题关键就是要构图。把顾客看作除开源点和汇点之外的节点。源点和汇点另设。

源点和每个猪圈的第一个顾客连上边,容量就是猪圈的数量。如果有重边就合并(比如第1个猪圈的第一个顾客是v1,第二个猪圈的第一个顾客是v1,那么从源点到v1就有重边,合并后的权值就是3+1=4。)

不是第一个顾客就跟上一个顶点连上边,权值是正无穷。

顾客要购买的数量就是vi到汇点的权值。

建好图之后就进行dinic 连续最短增广。用EK算法的也写过,会超时。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cctype>
using namespace std;
#define MAXN 1001
#define INF 2000000
#define min(a,b) (a)<(b)? a:b
int cap[MAXN][MAXN],flow[MAXN][MAXN];
int n,m;
int a[MAXN];
int vit[MAXN],lev[MAXN];
bool bfs(int st,int ed,int beg,int End)
{
    int que[MAXN];
    int Front,rear;
    Front=rear=0;
    que[Front++]=beg;
    memset(vit,0,sizeof(vit));
    vit[beg]=1;
    lev[beg]=0;
    while(rear<Front)
    {
        int t=que[rear];
        rear++;
        for(int i=st;i<=ed;i++)
        {
            if(cap[t][i]>flow[t][i]&&!vit[i])
            {
                que[Front++]=i;
                vit[i]=1;
                lev[i]=lev[t]+1;
            }
        }
    }
    return lev[End]<INF;

}
int dfs(int v,int st,int ed,int beg,int fl)
{
    int ret=0;
    if(v == n+1||fl==0)
        return fl;
    for(int i=st;i<=ed;i++)
    {
        if(fl==0)
            break;
        if(cap[v][i]>flow[v][i]&&lev[v]+1==lev[i])
        {
            int f=min(cap[v][i]-flow[v][i],fl);
            int r = dfs(i,st,ed,beg,f);
            ret+=r;
            fl-=r;
            flow[v][i]+=r;
            flow[i][v]-=r;
        }
    }
    return ret;
}
int dinic(int st,int ed,int beg,int End)
{
    int ret=0;
    while(bfs(st,ed,beg,End))
    {
        int r=dfs(beg,st,ed,beg,INF);
        if(r == 0)
            break;
        ret+=r;
    }
    return ret;
}
int main()
{
    int flag[MAXN];
    while(cin>>m>>n)
    {
        int s,t;
        s=0,t=n+1;
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=m;i++)
            cin>>a[i];
        for(int i=1;i<=n;i++)
        {
            int num,k;
            cin>>num;
            for(int j=0;j<num;j++)
            {
                cin>>k;
                if(!flag[k])
                    cap[s][i]+=a[k];
                else
                    cap[flag[k]][i]=INF;
                flag[k]=i;//前一个顾客
            }
            cin>>cap[i][t];
        }
        memset(flow,0,sizeof(flow));
        cout<<dinic(0,n+1,0,n+1)<<endl;
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值