ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing 2237. 猪

2022-07-06 12:05:17  阅读:151  来源: 互联网

标签:cur idx int ne 2237 猪舍 顾客 AcWing


POJ 1149 Pig/AcWing2237 猪

分析

本题还是蛮有意思的,我们来理顺一下思维过程。

我们总结一下,题目的操作。

每名顾客按顺序进行

  1. 将自己有钥匙的猪舍打开,从中挑选一些不超过自己想买的数量的猪。
  2. 同时可以将,打开的猪舍中的猪进行调整

这里面,我们需要一个逆向思维

我们考虑打开的猪舍中的所有猪都先被顾客取走,然后只拿走自己想要的部分,其余部分在自由的返回给打开的猪舍中

我们首先考虑的是,那我们是否可以直接,从顾客能打开的猪舍向顾客连一条边,接着再从顾客向所有能打开的猪舍连一条边,容量都是无穷

不行,这显然是不对的,因为我们需要考虑顺序问题,每一位顾客是在上一位的基础上挑选的。是不是发现了什么, 我们发现,这是逐层递推的,那我们可以建立分层图,以顾客的顺序建立,这样就能一步步递推了。

好啦,这就是我们的最基础写法。

分层图+网络流

这是最慢的写法了,在POJ上跑了三百多毫秒

接下来,我们考虑优化。

第一种优化

我们考虑,当前顾客与之前的顾客有一个猪舍重合,则当前顾客就可以取到之前的顾客所能触及到的所有猪舍

这样,我们就将时序的概念破坏,变成了一个二分图多重匹配的问题。

我们可以用bitset,优化判断是否有猪舍重合与将两者的猪舍合并的这个过程。

具体过程可以看看大佬的博客。whsstory

第二种优化

我们可以发现,对于最基础的方法,我们建立分层图之后。

我们可以发现,若我们当前的顾客与之前的顾客有一个猪舍重合,则当前的顾客所能得到猪的途径,则会多一条可以从之前的顾客手中得到猪的路径。因为如果我们想一个顾客取猪时,是先将能得到的猪全部取到手,再将剩余部分任意放回猪舍。则可以想成,若当前顾客与之前顾客有一个猪舍重合,则理解为,可以从之前的顾客手中得到猪。

也就是说,若当前顾客与之前顾客有一个猪舍重合,则我们可以直接从之前的顾客直接向当前顾客连一条容量为无穷的边。

初始时,若一个猪舍没有给任何顾客过,则从源点连接一条容量为猪舍初始数量的边。再从每一个顾客想汇点连接一条容量为最多购买数量的边。

这个就是最优写法了。

其思路,可以说是从分层图中得到的,我们从分层图中发现可以顾客顺序间,互相之间的连接关系。

AC_code

分层图+网络流

#include<bits/stdc++.h>

using namespace std;

const int N = 100110,M = (200000 + 1000 + 100)*2 + 10,INF = 0x3f3f3f3f;

int h[N],e[M],ne[M],f[M],idx;
int cur[N],q[N],d[N];
bool st[1010];
int n,m,S,T;

void add(int a,int b,int c)
{
    e[idx] = b,ne[idx] = h[a],f[idx] = c,h[a] = idx++;
    e[idx] = a,ne[idx] = h[b],f[idx] = 0,h[b] = idx++;
}

int get(int i,int t)
{
    return (t-1)*n + i;
}

bool bfs()  // 创建分层图
{
    int hh = 0, tt = 0;
    memset(d, -1, sizeof d);
    q[0] = S, d[S] = 0, cur[S] = h[S];
    while (hh <= tt)
    {
        int t = q[hh ++ ];
        for (int i = h[t]; ~i; i = ne[i])
        {
            int ver = e[i];
            if (d[ver] == -1 && f[i])
            {
                d[ver] = d[t] + 1;
                cur[ver] = h[ver];
                if (ver == T) return true;
                q[ ++ tt] = ver;
            }
        }
    }
    return false;  // 没有增广路
}

int find(int u, int limit)  // 在残留网络中增广
{
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        cur[u] = i;  // 当前弧优化
        int ver = e[i];
        if (d[ver] == d[u] + 1 && f[i])
        {
            int t = find(ver, min(f[i], limit - flow));
            if (!t) d[ver] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic()
{
    int r = 0, flow;
    while (bfs()) while (flow = find(S, INF)) r += flow;
    return r;
}

int main()
{
    scanf("%d%d", &n, &m);
    S = 0,T = N - 1;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        add(S,i,x);
    }
    for(int i=1;i<=m;i++)
    {
        int a;scanf("%d",&a);
        memset(st, 0, sizeof st);
        while(a--)
        {
            int x;scanf("%d",&x);
            st[x] = 1;
            add(get(x,i),i+n*m,INF);
            if(i!=m) add(i+n*m,get(x,i+1),INF);
        }
        int b;scanf("%d",&b);
        add(i+n*m,T,b);
        if(i!=m){
            for(int j=1;j<=n;j++)
                if(!st[j])
                    add(get(j,i),get(j,i+1),INF);
        }
    }
    
    printf("%d\n",dinic());
    return 0;
}

第二种优化

#include<bits/stdc++.h>
using namespace std;
const int N = 110,M = 20200,INF = 1e8;
int h[N],e[M],ne[M],w[M],idx;
int d[N],cur[N];
int g[1010],last[1010];
int m,n,S,T;

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
    e[idx]=a,ne[idx]=h[b],w[idx]=0,h[b]=idx++;
}

bool bfs()
{
    queue<int> q;
    memset(d,-1,sizeof d);
    d[S] = 0,cur[S] = h[S],q.push(S);
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        for(int i=h[t];~i;i=ne[i])
        {
            int j = e[i];
            if(d[j]==-1&&w[i])
            {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if(j==T) return 1;
                q.push(j);
            }
        }
    }
    return 0;
}

int find(int u,int limit)
{
    if(u==T) return limit;
    int flow = 0;
    for(int i=cur[u];~i&&flow<limit;i=ne[i])
    {
        cur[u] = i;
        int j = e[i];
        if(d[j]==d[u]+1&&w[i])
        {
            int t = find(j,min(w[i],limit-flow));
            if(!t) d[j] = -1;
            w[i] -= t,w[i^1] += t,flow += t;
        }
    }
    return flow;
}

int dinic()
{
    int r = 0,flow;
    while(bfs()) while(flow=find(S,INF)) r+=flow;
    return r;
}

int main()
{
    cin>>m>>n;
    memset(h, -1, sizeof h);
    S = 0,T = n + 1;
    for(int i=1;i<=m;i++) cin>>g[i];
    for(int i=1;i<=n;i++)
    {
        int a;cin>>a;
        while(a--)
        {
            int id;cin>>id;
            if(!last[id]) add(S,i,g[id]);
            else add(last[id],i,INF);
            last[id] = i;
        }
        int b;cin>>b;
        add(i,T,b);
    }
    
    cout<<dinic()<<endl;
    return 0;
}

标签:cur,idx,int,ne,2237,猪舍,顾客,AcWing
来源: https://www.cnblogs.com/aitejiu/p/16450269.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有