poj1149 最大流好题 难在建图 好题

  这个题的意思是有M个猪圈, N个人, 每个人按次序可以访问一些猪圈并可以买走一定数量的猪, 并且一个人用自己所拥有的猪圈钥匙打开猪圈后这些猪可以重新分配到已经打开的猪圈中, 问你可以买的最多的猪是多少个?强烈推荐看这个博文, 非常感谢博主

http://ycool.com/post/zhhrrm6

  代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;
const int inf = 0x3fffffff;
const int maxn = 2000+10;

struct Dinic
{
    int n;
    struct edge { int from, to, cap; };
    vector<int> G[maxn];
    vector<edge> e;
    int level[maxn], iter[maxn];
    void init()
    {
        for(int i=0; i<=n; i++) G[i].clear();
        e.clear();
    }
    void add_edge(int u, int v, int cap)
    {
        e.push_back((edge){u, v, cap});
        e.push_back((edge){v, u, 0});
        int m = e.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
    }
    void bfs(int s)
    {
        memset(level, -1, sizeof(level));
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(!que.empty())
        {
            int u = que.front();  que.pop();
            for(int i=0; i<G[u].size(); i++)
            {
                edge &te = e[G[u][i]];
                if(te.cap>0 && level[te.to]<0)
                {
                    level[te.to] = level[u] + 1;
                    que.push(te.to);
                }
            }
        }
    }
    int dfs(int v, int t, int f)
    {
        if(v == t) return f;
        for(int &i=iter[v]; i<G[v].size(); i++)
        {
            edge& tpe = e[G[v][i]];
            if(tpe.cap>0 && level[v]<level[tpe.to])
            {
                int d = dfs(tpe.to, t, min(f, tpe.cap));
                if(d > 0)
                {
                    tpe.cap -= d;
                    e[G[v][i]^1].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int max_flow(int s, int t)
    {
        int flow = 0;
        for(;;)
        {
            bfs(s);
            if(level[t]<0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f=dfs(s, t, 0x3fffffff)) > 0)
                flow += f;
        }
        return flow;
    }
}di;
int pignum[1000+10];
int f[1000+10];       //i猪圈最后访问的人是哪一个
int G[105][105];

int main()
{
    int M, N;
    scanf("%d%d", &M, &N);
    di.n = N+2;   //0超级源点 N+1超级汇点
    di.init();
    for(int i=1; i<=M; i++) scanf("%d", &pignum[i]);
    memset(f, -1, sizeof(f));
    memset(G, -1, sizeof(G));
    for(int i=1; i<=N; i++)
    {
        int v = i;
        int keynum;
        scanf("%d", &keynum);
        for(int i=0; i<keynum; i++)
        {
            int u = 0, t, cap;
            scanf("%d", &t);
            if(f[t] == -1)
            {
                cap = pignum[t];
                G[u][v] = (G[u][v]==-1?cap:G[u][v]+cap);
                f[t] = v;
            }
            else
            {
                u = f[t];
                cap = inf;
                G[u][v] = inf;
                f[t] = v;
            }
        }
        int ndnum;
        scanf("%d", &ndnum);
        G[v][N+1] = ndnum;
    }
    for(int i=0; i<N+2; i++)
        for(int j=0; j<N+2; j++) if(G[i][j] != -1)
        di.add_edge(i, j, G[i][j]);
    printf("%d\n", di.max_flow(0, N+1));
    return 0;
}

 

转载于:https://www.cnblogs.com/xingxing1024/p/5237212.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值