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 Pigs 题解的更多相关文章

  1. POJ1149:PIGS——题解

    http://poj.org/problem?id=1149 题目大意: Mirko有M个猪圈和N个客户,猪圈里有特定数量的猪,每个客户按照顺序来买猪,他们只能打开他们能打开的猪圈,然后取走一些猪(上 ...

  2. [Leetcode Week6]Best Time to Buy and Sell Stock

    Best Time to Buy and Sell Stock 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/best-time-to-buy-and ...

  3. [LeetCode 题解]:Best Time to Buy and Sell Stock

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述 Say you ha ...

  4. Lintcode393 Best Time to Buy and Sell Stock IV solution 题解

    [题目描述] Say you have an array for which the i th element is the price of a given stock on day i. Desi ...

  5. [LeetCode]题解(python):123-Best Time to Buy and Sell Stock III

    题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ 题意分析: 和上题类似,array[i]代表第i天物品 ...

  6. [LeetCode]题解(python):122-Best Time to Buy and Sell Stock II

    题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ 题意分析: 和上题类似,给定array,代表第i天物品i ...

  7. [LeetCode]题解(python):121-Best Time to Buy and Sell Stock

    题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 题意分析: 给定一个数组,代表array[i] 代表第i天的价 ...

  8. 题解 POJ1149 Pigs

    先翻译一下吧(题面可以在原OJ上找) Mirko在一个由M个锁着的猪舍组成的养猪场工作,Mirko无法解锁任何猪舍,因为他没有钥匙.客户纷纷来到农场.他们每个人都有一些猪舍的钥匙,并想购买一定数量的猪 ...

  9. CF116B Little Pigs and Wolves 题解

    Content 有一张 \(n\times m\) 的地图,其中,\(\texttt{P}\) 代表小猪,\(\texttt{W}\) 代表狼.如果狼的上下左右有一头以上的小猪,那么它会吃掉其中相邻的 ...

  10. [题解] Codeforces 1548 C The Three Little Pigs 组合数学,生成函数

    题目 首先令\(x=i\)时的答案为\(f_i\) ,令\(f_i\)对应的普通生成函数为\(F(x)\). 很容易发现\(F(x)=\sum_{i=0}^n (1+x)^{3i}\),sigma是在 ...

随机推荐

  1. 【阅读笔记】提升example-based SISR七个技巧

    论文信息 [Seven ways to improve example-based single image super resolution]-Radu Timofte, 2016, CVPR 论文 ...

  2. C标准库 操作文件

    C标准库 操作文件 数据持久化的两种方法:文件和数据库 文本文件和二进制文件 举个例子,写C++的代码,源代码为文本文件.编译出来的可执行文件(.exe)文件是二进制文件 文本文件 以文本的编码(AS ...

  3. js将数字金额转换成中文金额格式

    在开发中我们经常会遇到处理数字的问题,下面介绍一种处理数字金额转换为中文金额的方式: 我们通常使用三种书面数字系统:全球使用的阿拉伯数字系统和两种本地数字系统(繁体.简体).常规时我们使用阿拉伯数字( ...

  4. 王道oj/problem20

    网址:oj.lgwenda.com/problem/20 思路:层次建树,用递归的方法前序遍历 代码: #define _CRT_SECURE_NO_WARNINGS#include <stdi ...

  5. 七 APPIUM Android 定位方式(转)

    1.定位元素应用元素 1.1通过id定位元素 Android里面定位的id一般为resrouce-id: 代码可以这样写: WebElement element = driver.findElemen ...

  6. C#.NET 国密SM2 签名验签 与JAVA互通 ver:20230807

    C#.NET 国密SM2 签名验签 与JAVA互通 ver:20230807 .NET 环境:.NET6 控制台程序(.net core). JAVA 环境:JAVA8(JDK8,JAVA 1.8), ...

  7. 使用MkDocs搭建个人博客

    使用MkDocs搭建个人博客 接触编程已经好几年了,阅读了无数大佬的博客文章,但是从来没有自己写过.这其中最重要的原因当然是懒惰,觉得写博客太费时间了,对自己的帮助也不大.可是如今发现自己的记性越来越 ...

  8. 《Pro Git》起步笔记

    @ 目录 什么是版本控制 本地版本控制系统 集中化的版本控制 分布式的版本控制系统 Git简史 Git是什么 安装Git 在Linux上安装 在Windows上安装 初次运行Git前的配置 用户信息 ...

  9. 《Redis核心技术与实战》学习笔记总结目录

    1 Redis学习路径 去年我学习了极客时间的<Redis核心技术与实战>课程,在这门课程的学习中,我经常看到一位课代表的发言,他就是Kaito,他总结了一份Redis学习路径脑图(建议收 ...

  10. MIT6.s081/6.828 lectrue07:Page faults 以及 Lab5 心得

    本篇博客主要是复习 MIT6.s081/6.828 lectrue07:Page faults 以及记录 Lab5 :COW fork 的心得 值得一提的是,2020 年之前的版本第 5 个 lab ...