poj 1149 网络流

构图:源点向每个顾客连买猪数目的边,若顾客是第一个来到该猪圈的,则像猪圈连一条猪圈猪数目的边

,否则像上一个来到该猪圈的顾客连一条inf的边,猪圈向汇点连接一条猪圈猪数目的边,最大流

用了dinic算法

 

#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int inf=1<<30;
const int maxn=2001;
int a[maxn];


struct
{
    int to,w,next;
}e[300001];


int lon=1,head[maxn];


int edgeini(int n)
{
    for(int i=0;i<n;i++) head[i]=-1;
}


int edgemake(int from,int to,int w)
{
    e[++lon].to=to;
    e[lon].w=w;
    e[lon].next=head[from];
    head[from]=lon;
    e[++lon].to=from;
    e[lon].w=0;
    e[lon].next=head[to];
    head[to]=lon;
}




int level[maxn];
int makelevel(int s,int t)
{
    memset(level,0,sizeof(level));
    level[s]=1;
    int top=0;
    int que[maxn];
    que[++top]=s;
    for(int i=1;i<=top;i++)
    {
        int u=que[i];
//        printf("%d %d\n",u,level[u]);
        if(u==t) return(1);
        for(int k=head[u];k!=-1;k=e[k].next)
        if(!level[e[k].to]&&e[k].w)
        {
            que[++top]=e[k].to;
            level[e[k].to]=level[u]+1;
        }
    }
    return(0);
}


int dfs(int now,int maxf,int t)
{
    if(now==t) return(maxf);
    int ret=0;
    for(int k=head[now];k!=-1;k=e[k].next)
    {
        if(e[k].w&&level[e[k].to]==level[now]+1)
        {
            int f=dfs(e[k].to,min(maxf-ret,e[k].w),t);
            e[k].w-=f;
            e[k^1].w+=f;
            ret+=f;
//            printf("%d %d\n",ret,maxf);
            if(ret==maxf) return(ret);
        }
    }
    return(ret);
}






int dinic(int s,int t)
{
    int ans=0;
    while(makelevel(s,t)) ans+=dfs(s,inf,t);
    return(ans);
}


int main()
{
    edgeini(maxn);
    int m,n;
    scanf("%d %d",&m,&n);
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    int last[maxn];
    memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        int txt;
        for(int j=1;j<=tmp;j++)
        {
            scanf("%d",&txt);
            if(last[txt]==0)
            {
                edgemake(i,txt+n,inf);
            }
            else
            {
                edgemake(i,last[txt],inf);
            }
            last[txt]=i;
        }
        scanf("%d",&txt);
        edgemake(0,i,txt);
    }
    for(int i=1;i<=m;i++)
    edgemake(i+n,n+m+1,a[i]);
    int ans=dinic(0,n+m+1);
    printf("%d\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值