poj-1149-PIGS-网络流

本文介绍了一种使用最大流算法解决特定问题的方法:即如何在顾客拥有不同猪圈钥匙的情况下,通过重新分配猪只来最大化销售数量。文章详细阐述了算法实现过程,包括网络构建、边权设置及具体步骤。

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

题意:M个猪圈,N个顾客,每个顾客有一些的猪圈的钥匙,只能购买这些有钥匙的猪圈里的猪,而且要买一定数量的猪,每个猪圈有已知数量的猪,
但是猪圈可以重新打开,将猪的个数,重新分配,以达到卖出的猪的数量最多。
①构造网络,将顾客看成源点和汇点以外的结点,并设另外两个节点:源点和汇点。
②源点和每个猪圈的第一个顾客连边,边的权是开始时候猪圈中猪的数量。
③ 若源点和某个节点之间有重边,则将权合并
④顾客j紧跟顾客i之后打开某个猪圈,则<i.j>的权是正无穷。
⑤每个顾客和会点之间连边,边的权值是顾客所希望购买的猪的数量。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include<queue>
using namespace std;
#define INF 99999999
const int maxn =1110;
const int maxm =220000;
const int oo = 1<<29;
struct Arclist
{
    int cnt, head[maxn], dis[maxn];
    int cur[maxn], pre[maxn], gap[maxn], aug[maxn];
    struct node
    {
        int u, v, w, next;
    }edge[maxm];
    void init()
    {
        cnt = 0;
        memset(head,-1,sizeof(head));
    }
    void add(int u, int v, int w)
    {
       // cout<<u<<" "<<v<<" "<<w<<endl;
        edge[cnt].u = u;
        edge[cnt].v = v;
        edge[cnt].w = w;
        edge[cnt].next = head[u];
        head[u] = cnt++;
        edge[cnt].u = v;
        edge[cnt].v = u;
        edge[cnt].w = 0;
        edge[cnt].next = head[v];
        head[v] = cnt++;
    }
    int sap(int s, int e, int n)
    {
        int max_flow = 0, u = s;
        int mindis;
        for(int i = 0; i <= n; i++)
        {
            cur[i] = head[i];
            dis[i] = 0;
            gap[i] = 0;
        }
        aug[s] = oo;
        pre[s] = -1;
        gap[0] = n;
        while(dis[s]<n)
        {
            bool flag = false;
            if(u==e)
            {
                max_flow += aug[e];
                for(int v = pre[e]; v != -1; v = pre[v])
                {
                    int id = cur[v];
                    edge[id].w -= aug[e];
                    edge[id^1].w += aug[e];
                    aug[v] -= aug[e];
                    if(edge[id].w==0) u = v;
                }
            }
            for(int id = cur[u]; id != -1; id = edge[id].next)
            {
                int v = edge[id].v;
                if(edge[id].w>0 && dis[u]==dis[v]+1)
                {
                    flag = true;
                    pre[v] = u;
                    cur[u] = id;
                    aug[v] = std::min(aug[u], edge[id].w);
                    u = v;
                    break;
                }
            }
            if(flag==false)
            {
                if(--gap[dis[u]]==0) break;
                mindis = n;
                cur[u] = head[u];
                for(int id = head[u]; id != -1; id = edge[id].next)
                {
                    int v = edge[id].v;
                    if(edge[id].w>0 && dis[v]<mindis)
                    {
                        mindis = dis[v];
                        cur[u] = id;
                    }
                }
                dis[u] = mindis+1;
                ++gap[dis[u]];
                if(u!=s) u = pre[u];
            }
        }
        return max_flow;
    }
}G;
int w[maxn];
int pre[maxn];
int main()
{
    int n,m,i,j,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        G.init();
        memset(pre,0,sizeof(pre));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d",&a);
            for(j=1;j<=a;j++)
            {
                scanf("%d",&b);
                if(pre[b]==0)G.add(0,i,w[b]);
                else G.add(pre[b],i,INF);
                pre[b]=i;
            }
            scanf("%d",&a);
            G.add(i,m+1,a);
        }
        cout<<G.sap(0,m+1,m+2)<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值