首页 > 其他分享 >Sell Pigs 题解

Sell Pigs 题解

时间:2023-06-05 17:01:26浏览次数:40  
标签:Sell head idx int 题解 边权 Pigs 猪圈 顾客

Sell Pigs

双倍经验

题目大意

有 \(n\) 个顾客前来买猪,共有 \(m\) 个猪圈,每个顾客携带着某一些猪圈的钥匙,需要买一定数量的猪。在顾客买完后,我们可以将打开的猪圈中的猪随意移动,移动完毕后所有的猪圈将关闭,直到下一个顾客到来时才能打开其拥有钥匙对应的猪圈。求最多能卖出多少猪。

思路分析

我们注意到顾客是有时间顺序的。因此,我们首先想到可以建立一张分层图,每个点 \((a,b)\) 表示在第 \(a\) 个顾客到来时的第 \(b\) 个猪圈, 那么边的设置就很自然:

  • 建立虚拟源点和汇点,源点向每个 \((1,x)\) 点连边,边权为初始的数量。
  • 对于每一层再建一个点,将该层所有被打开的点向它连边,同时它向下一层对于的点连边,边权均为 \(+\infty\),再将其向汇点连边,边权为 \(+\infty\)。

然后跑最大流就可以了。

但是,这样的空间复杂度是 \(O(nm)\) 的,时间复杂度更是高达 \(O(n^3m^3)\),是比较劣的,如何优化呢?

既然顾客有时间顺序,那么我们不妨从顾客下手,只建立 \(n\) 个代表顾客的点,那么如何连边呢?

  • 建立虚拟源点,汇点。
  • 每个点向汇点连边,边权是这个顾客对猪的需求量。
  • 记录每个猪圈最近一次是被谁打开的,如果是第一次打开,将从源点向这个顾客连的边的边权增加这个猪圈的猪的数量。(如果没有这条边就建立这条边)
  • 如果不是第一次打开,将上一次打开这个猪圈的顾客向这个顾客连一条边权是 \(+\infty\) 的边。

然后跑最大流就可以了。

空间复杂度 \(O(n)\),时间复杂度 \(O(n^3)\)。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=100100;
#define inf 0x3f3f3f3f

int to[N],nxt[N],head[N],w[N];
int idx=1,n,m,S,T,in1,in2;
int d[N],cur[N];queue <int> q;
int a[N],vis[N];//a 是猪圈中猪的数量,vis 保存上一次打开的人

void add(int u,int v,int c){
    idx++;to[idx]=v;nxt[idx]=head[u];head[u]=idx;w[idx]=c;
    idx++;to[idx]=u;nxt[idx]=head[v];head[v]=idx;w[idx]=0;
}

//dinic模板默写

bool bfs(){
    memset(d,-1,sizeof d);d[S]=0;
    while(!q.empty()) q.pop();
    cur[S]=head[S];q.push(S);
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=head[now];i;i=nxt[i]){
            int v=to[i];
            if(~d[v]||!w[i]) continue;
            d[v]=d[now]+1;cur[v]=head[v];
            if(v==T) return 1;q.push(v);
        }
    }
    return 0;
}

int dfs(int s,int lim){
    if(s==T) return lim;
    int flow=0;
    for(int i=cur[s];i&&flow<lim;i=nxt[i]){
        int v=to[i];cur[s]=i;
        if(d[v]!=d[s]+1||!w[i]) continue;
        int t=dfs(v,min(w[i],lim-flow));
        if(!t) d[v]=-1;
        w[i]-=t;w[i^1]+=t;flow+=t;
    }
    return flow;
}

int dinic(){
    int ans=0,flow=0;
    while(bfs()) while(flow=dfs(S,inf)) ans+=flow;
    return ans;
}

//------

int main(){
    scanf("%d%d",&m,&n);
    S=0;T=N-2;//虚拟源汇点
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        scanf("%d",&in1);
        int sum1=0;
        for(int j=1;j<=in1;j++){
            scanf("%d",&in2);
            if(!vis[in2]){sum1+=a[in2];}//增加边权
            else add(vis[in2],i,inf);//上一个人向这个人连边
            vis[in2]=i;//更新这个猪圈
        }
        if(sum1) add(S,i,sum1);
        scanf("%d",&in1);
        add(i,T,in1);//向汇点连边
    }
    cout<<dinic()<<'\n';
    return 0;
}

标签:Sell,head,idx,int,题解,边权,Pigs,猪圈,顾客
From: https://www.cnblogs.com/TKXZ133/p/17458259.html

相关文章

  • 旅游 题解
    旅游题目大意对一颗树进行两种操作:将一条从\(u\)到\(v\)的链上的点的权值增加\(x\);查询从\(u\)到\(v\)的链上最大的\(p_i-p_j(dis_{ui}<dis_{uj})\),其中\(p_i\)表示点\(i\)的权值,\(dis_{AB}\)表示点\(A,B\)间唯一路径上边的数量。思路分析先思考,如果没有\(d......
  • Interesting Array 题解
    InterestingArray题目大意构造一个序列\(a\),使其满足若干限制条件,每个限制条件是形如lrq的式子,其意义是:\(\&_{i=l}^ra_i=q\)。题意分析看上去是构造题,实际上是数据结构题。我们不妨先令初始时\(a\)为一个全\(0\)序列,再逐一看每个限制条件。为了满足某一个限制条件......
  • Sum of MSLCM 题解
    SumofMSLCM题目大意定义\(\text{MSLCM}(n)\)为所有满足该数集的\(\text{lcm}\)为\(n\)的数集中元素个数最多的数集的所有数字的和,现有多次询问,求\[\sum_{i=2}^n\text{MSLCM}(i)\]思路分析大水题。虽然看着这个东西很可怕,但仔细一想你就会发现,其实\(\text{MSLCM}(n)......
  • Java模拟表单提交编码不同导致乱码问题解决
    最近有个业务需要模拟表单提交到asp页面中,但是我的项目编码是UTF8,而asp页面是GB2312,中文字段提交后,到达数据库后是乱码.问题的解决在于模拟提交的时候指定编码:我用的HTTP框架是Unirest,代码如下:......
  • 安装Navicat遇到的问题解决
    1、如果遇到安装出现问题,并且不能激活,需要重新卸载安装。需要彻底卸载2、除了点击卸载安装之后,需要注册表删除掉所有的信息,以及删除掉在C:\ProgramFiles\PremiumSoft的Navicat删除掉3、删除注册表Win+R之后输入:regedit进入注册表3.1找到计算机\HKEY_CURRENT_USER\Softwar......
  • [ABC208E] Digit Products 题解
    DigitProducts题目大意求有多少个不大于\(n\)的正整数,使得该正整数各位乘积不大于\(k\)。思路分析观察数据范围,首先考虑数位DP。考虑设计记忆化搜索函数dfs(intpos,boollimit,boollead0,intmul)表示当前枚举到第\(\text{pos}\)位,第\(\text{pos}\)位是否受到限......
  • [ABC207E] Mod i 题解
    Modi题目大意给定一个序列\(a\),问将其划分成若干段,满足第\(i\)段的和是\(i\)的倍数的划分方案的个数。思路分析考虑DP,设\(f_{i,j}\)表示将序列中前\(i\)个数划分成\(j\)段,且满足条件的划分方案的个数,容易得出状态转移方程:\[f_{i,j}=\sumf_{k,j-1}(\sum_{h=k+1}......
  • [ABC205E] White and Black Balls 题解
    WhiteandBlackBalls题目大意将\(n\)个白球,\(m\)个黑球排成一列,要求满足\(\foralli\in[1,n+m],w_i\leb_i+k\),问存在多少种排法。其中\(w_i\)表示第\(i\)个球前的白球数量,\(b_i\)表示第\(i\)个球前的黑球数量。思路分析我们可以将一种排法映射成一条从\((0,0)......
  • [ABC205F] Grid and Tokens 题解
    GridandTokens题目大意给定\(n\)个点和一个\(H\timesW\)的网格,每个点可以放置在\((A_i,B_i)\)到\((C_i,D_i)\)的矩形中或不放,每一行或一列只能放置一个点,求最多能放多少个点。思路分析首先看数据范围,再结合题目给的限制条件,容易发现这是一道网络流。考虑建图,因为......
  • [ABC201E] Xor Distances 题解
    XorDistances题目大意给定一颗带边权无根树,定义\(\text{dis}(i,j)\)表示\(i,j\)两点在树上的最短路径的边权的异或和。求:\[\sum_{i=1}^n\sum_{j=i+1}^n\text{dis}(i,j)\]思路分析首先,容易证明:\[\text{dis}(i,j)=\text{dis}(i,x)\oplus\text{dis}(x,j)\]这个式子告诉我......