(POJ1149)PIGS(建图+EK模板,Ford-fulkerson)

PIGS
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 19792 Accepted: 9062
Description

Mirko works on a pig farm that consists of M locked pig-houses and Mirko can’t unlock any pighouse because he doesn’t have the keys. Customers come to the farm one after another. Each of them has keys to some pig-houses and wants to buy a certain number of pigs.
All data concerning customers planning to visit the farm on that particular day are available to Mirko early in the morning so that he can make a sales-plan in order to maximize the number of pigs sold.
More precisely, the procedure is as following: the customer arrives, opens all pig-houses to which he has the key, Mirko sells a certain number of pigs from all the unlocked pig-houses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses.
An unlimited number of pigs can be placed in every pig-house.
Write a program that will find the maximum number of pigs that he can sell on that day.
Input

The first line of input contains two integers M and N, 1 <= M <= 1000, 1 <= N <= 100, number of pighouses and number of customers. Pig houses are numbered from 1 to M and customers are numbered from 1 to N.
The next line contains M integeres, for each pig-house initial number of pigs. The number of pigs in each pig-house is greater or equal to 0 and less or equal to 1000.
The next N lines contains records about the customers in the following form ( record about the i-th customer is written in the (i+2)-th line):
A K1 K2 … KA B It means that this customer has key to the pig-houses marked with the numbers K1, K2, …, KA (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0.
Output

The first and only line of the output should contain the number of sold pigs.
Sample Input

3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6
Sample Output

7
Source

Croatia OI 2002 Final Exam - First day

题意:
有个农场,有多个猪圈。开始时猪圈都是关着的,每次有顾客前来卖猪,顾客有某些猪圈的要是和要买猪的数量,再顾客买完后,Mirko可以重新分配打开了的猪圈的猪的数量。问最多可以卖出多少猪。

分析:
这题最大的难点就是建图。首先我们知道这是一个网络流的问题,那么我们可以怎么样是思考呢?什么是始点,什么是汇点,中间节点又是什么?由于题目最终是将猪卖出去,所有始点代表整个农场,汇点代表卖出去的猪。那猪是怎么出去的呢?是通过顾客出去的,所以说中间节点是顾客。
所以建图如下:
1:始点和所有猪圈的第一个顾客连边,权值为猪圈中猪的数量。由于某个顾客可能是几个猪圈的第一个顾客,所以将权值相加。
2:顾客j紧接着顾客i之后打开某猪圈,则有边< i,j> 权值为INF,这是因为j紧接着i打开某个猪圈,那么 Mirko可以根据j的需求,将其他的猪圈的猪调整过来。
3:每个顾客和汇点有一条边,权值为买猪的数量。
建完边后求最大流即可。

Ford-fulkerson:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>

using namespace std;

const int maxn=110;
const int maxm=1010;
const int INF=100000;
int s,t,n,m;
int c[maxn][maxn];//容量
int flow[maxn][maxn];//流量
queue<int> q;

void init()
{
    int num,k,w;
    int house[maxm],last[maxm];//猪圈中猪的数量,上一个打开的顾客编号
    memset(last,0,sizeof(last));
    memset(c,0,sizeof(c));
    memset(flow,0,sizeof(flow));
    s=0;t=n+1;
    for(int i=1;i<=m;i++)
        scanf("%d",&house[i]);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
        for(int j=0;j<num;j++)
        {
            scanf("%d",&k);
            if(last[k]==0)
                c[s][i]+=house[k];
            else
                c[last[k]][i]=INF;
            last[k]=i;
        }
        scanf("%d",&w);
        c[i][t]+=w;
    }
}

void ford()
{
    int pre[maxn];
    int alpha[maxn];
    int v;
    memset(alpha,0,sizeof(alpha));
    alpha[0]=INF;
    while(1)
    {
        memset(pre,-1,sizeof(pre));
        pre[0]=0;
        while(!q.empty())
            q.pop();
        q.push(0);
        while(!q.empty() && pre[t]==-1)
        {
            v=q.front();
            q.pop();
            for(int i=0;i<=t;i++)
            {
                if(pre[i]==-1 && c[v][i]>flow[v][i])
                {
                    pre[i]=v;q.push(i);
                    alpha[i]=min(alpha[v],c[v][i]-flow[v][i]);
                }
            }
        }
        if(pre[t]==-1) break;
        //调整
        int k1=pre[t],k2=t;
        while(1)
        {
            flow[k1][k2]+=alpha[t];
            flow[k2][k1]-=alpha[t];
            if(k2==0) break;
            k2=k1;k1=pre[k1];
        }
    }
    int ans=0;
    for(int i=0;i<t;i++)
        ans+=flow[i][t];
    printf("%d\n",ans);
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        init();
        ford();
    }
    return 0;
}

EK

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>
#define init(a) memset(a,0,sizeof(a))
#define PI acos(-1,0)
using namespace std;
const int maxn = 500;
const int maxm = 40000;
#define lson left, m, id<<1
#define rson m+1, right, id<<1|1
#define min(a,b) (a>b)?b:a
#define max(a,b) (a>b)?a:b
#define MAX INT_MAX

int c[1000][1000];
int re[1000];
int f[1000][1000];
int p[1000],n,m;

void EK(int s,int t)
{
    queue<int >q;
    while(q.empty()==false) q.pop();
    int sum = 0;
    while(1)
    {
        memset(re,0,sizeof(re));
        q.push(s);
        re[s] = MAX;
        p[s] = -1;
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int i = 1;i<=n+1;i++)
            {
                if(!re[i] && f[u][i] < c[u][i])
                {
                    q.push(i);
                    p[i] = u;
                    re[i] = min(re[u],c[u][i]-f[u][i]);
                }
            }
        }
        if(re[t]==0) break;
        for(int st = t;st!=s;st = p[st])
        {
            f[p[st]][st] += re[t];
            f[st][p[st]] -= re[t];
        }
        sum += re[t];
    }
    printf("%d\n",sum);
}
void initt()
{
    for(int i = 0;i<=n+1;i++)
    {
        for(int j = 0;j<=n+1;j++)
        {
            c[i][j] = f[i][j] = 0;
        }
        p[i] = 0;
    }
}
int main()
{
    int pig[1001];
    int a,b,w;
    while(~scanf("%d%d",&m,&n))
    {
        initt();
        for(int j = 1;j<=m;j++)
            scanf("%d",&pig[j]);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&a);
            while(a--)
            {
                scanf("%d",&b);
                if(!p[b])//判断当前猪圈是否打开过
                {
                    c[p[b]][i] += pig[b];
                    p[b] = i;
                }
                else
                {
                    c[p[b]][i] = MAX;//打开过说明,可以从其他猪圈流向本猪圈,流量可能为无限大
                    p[b] = i;
                }
            }
            scanf("%d",&w);
            c[i][n+1] += w;
        }
        EK(0,n+1);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值