Luogu P2754 星际转移问题

思路

首先,对于地球能否到达月球的问题,考虑使用并查集维护。

对于每艘飞船能够到达的站点,放进一个集合里,若两艘飞船的集合有交集,那么就合并两个集合,最后只要地球和月亮在同一个集合里即可到达。

然后就是多少天送完的问题。

想要最少天数送完,那么每次就尽可能地多送,考虑最大流。

那么怎么建图?

先放 \(n+4\) 个点( \(n\) 个空间站 + 地球和月球 + 源点 +汇点 ),想当然地,源点-->地球,容量为 \(k\) (初始时地球上的人数),月球指向汇点,容量 \(inf\) 。(这里为了方便,地球为 \(0\) ,月球为 \(n+1\) )

那么怎么表示太空船在各个太空站之间的移动呢?

分层。

按时间分层。举个例子:存在第 \(i\) 艘飞船的航线为 \((3,1,2)\) ,那么在第一个时刻,它在第 \(3\) 个空间站;在第二个时刻,它在第 \(1\) 个空间站;以此类推。于是我们连接第一时刻的 \(3\) 与第二时刻的 \(1\) ,即 \((1,3)\) --> \((2,1)\) ,容量为 \(h_i\) (第 \(i\) 艘飞船的容量)。当 \((1,3)\) 有流向 \((2,1)\) 的流时,就表示第一时刻到第二时刻,有人乘坐第 \(i\) 艘飞船从空间站 \(3\) 到了空间站 \(1\) 。

这样便得到了一个横向为时间,纵向为站点的分层图。

又因为地球、月球、空间站的容量无限,所以各个站点在每个时刻联通,即 \((1,x)\) --> \((2,x)\) --> \((3,x)\) --> \(\dots\) , \(x\) 为 \(n+2\) 个站点中的任意一个,相当于人停在该站点不动。双因为,无论哪个时刻到达月球都算送达,所以每个时刻的月球都向 \(t\) 连边,即 \((y,n+1)\) --> \(t\) ,\(y\) 为任意一个时刻。

最后从 \(1\) 开始枚举时间,直到源点流出的 \(k\) 份流量全部流入了汇点再跳出。

/*   卑劣的手打示意分层图
time-> ans
place da1 da2 ... ans
| earth 0_1 0_2 ... 0_ans
V station_1 1_1 1_1 ... 1_ans
. . . ... .
. . . ... .
n+1 moon n+1_1 n+1_2 ... n+1_ans
*/

样例建图如下:

直到第六个时刻,该网络的最大流才为 \(1\) ,共历时 \(5\) 个时刻,答案为 \(5\) 。

Code

#include<bits/stdc++.h>
//#define int long long //祖宗
#define mp(a,b) make_pair(a,b)
using namespace std;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int N=3000,M=5e5+5;
int first[N],nex[M],to[M],w[M],num=1;
int n,m,k,s,t,ans,Maxflow;
int h[N],r[N],p[25][25];
inline void add(int u,int v,int val)
{
nex[++num]=first[u];
first[u]=num;
to[num]=v;
w[num]=val;
}
inline void Add(int u,int v,int val)
{
add(u,v,val);
add(v,u,0);
}
namespace ISAP
{
int dep[N],gap[N],cur[N],NUM;
void bfs()
{
memset(dep,-1,sizeof(dep));
queue<int> q;
q.push(t);
dep[t]=0;gap[0]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=first[u];i;i=nex[i])
{
int v=to[i];
if(dep[v]!=-1) continue;
dep[v]=dep[u]+1;
gap[dep[v]]++;
q.push(v);
}
}
}
inline int dfs(int u,int in)
{
if(u==t) return in;
int out=0;
for(int i=cur[u];i;i=nex[i])
{
cur[u]=i;
int v=to[i];
if(!w[i]||dep[v]!=dep[u]-1) continue;
int res=dfs(v,min(w[i],in-out));
w[i]-=res;
w[i^1]+=res;
out+=res;
if(out==in) return out;
}
gap[dep[u]]--;
if(!gap[dep[u]]) dep[s]=NUM+1;
dep[u]++;
gap[dep[u]]++;
return out;
}
void work(int t)
{
NUM=(n+1)*(t+1)+2;//当前网络的点的个数(供ISAP用,如果你是Dinic就无视它)
bfs();
while(dep[s]<NUM)
{
memcpy(cur,first,sizeof(first));
Maxflow+=dfs(s,1e9);
}
}
}
namespace UFS//并查集,判断是否联通
{
int fa[N];
void init(){for(int i=0;i<N;++i) fa[i]=i;}
inline int getfa(int u)
{
if(fa[u]==u) return u;
return fa[u]=getfa(fa[u]);
}
inline void merge(int u,int v)
{
int a=getfa(u),b=getfa(v);
if(a!=b) fa[a]=b;
}
}
inline int turn(int t,int p){return (t-1)*(n+2)+p;}//将t时p地的位置转化为点的编号
main()
{//0->地球
//n+1->月球
using namespace UFS;
init();
n=read(),m=read(),k=read();s=N-1,t=N-2;
for(int i=1;i<=m;++i)
{
h[i]=read();r[i]=read();
for(int j=1;j<=r[i];++j)
{
p[i][j]=read();//第i艘船第j个站点的位置为p[i][j]
if(p[i][j]==-1) p[i][j]=n+1;
if(j!=1)merge(p[i][j],p[i][j-1]);
//位置p[i][j]与位置p[i][j+1]之间可以通过第i艘船到达
}
}
if(getfa(0)!=getfa(n+1))
{
printf("0");
return 0;
}
int ans=2;//枚举时间,t==1时,人都在地球上
Add(s,turn(1,0),k);//从源点到t==1时的地球
Add(turn(1,n+1),t,1e9);
Maxflow=0;
while(1)
{
Add(turn(ans,n+1),t,1e8);//从当前时刻的月亮到汇点
for(int i=0;i<=n+1;++i) Add(turn(ans-1,i),turn(ans,i),1e9);//与上一时刻
for(int i=1;i<=m;++i)
{
int a=turn(ans,p[i][(ans-1)%r[i]+1]);//第i艘船第ans时刻所在的点
int b=turn(ans-1,p[i][(ans-2)%r[i]+1]);//第i艘船第ans-1时刻所在的点
//分析一下就理解了
Add(b,a,h[i]);
}
ISAP::work(ans);//不用重置,每次加完边后在残余网络上跑,将每次流量累积即为该网络的最大流
if(Maxflow>=k)
{
printf("%d",ans-1);
return 0;
}
ans++;
}
return 0;
}

Luogu P2754 星际转移问题的更多相关文章

  1. 洛谷 P2754 星际转移问题【最大流】

    判无解的方法非常粗暴:快T了还是没有合法方案,就是无解. 然后枚举答案,对于每一天都建一套太空站,s连地球,t连月球,上一天的太空站连向这一天的太空站,流量均为inf.然后对于每个飞船,上一天的停靠站 ...

  2. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  3. 线性规划与网络流24题●09方格取数问题&13星际转移问题

    ●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为“技术”不佳,搞了一上午) ●09方格取数问题(codevs1907  方格取数3) 想了半天,也没成功建好图: 无奈下 ...

  4. [CTSC1999][网络流24题] 星际转移

    36. [CTSC1999][网络流24题] 星际转移 ★★★☆   输入文件:home.in   输出文件:home.out   简单对比时间限制:1 s   内存限制:128 MB «问题描述: ...

  5. 网络流24题之星际转移问题(洛谷P2754)

    洛谷 P2754 题目背景 none! 题目描述 由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,21 ...

  6. 【网络流24题】No. 13 星际转移问题 (网络判定 最大流)

    [题意] 由于人类对自然资源的消耗, 人们意识到大约在 2300 年之后, 地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民. 令人意想不到的是, 2177 年冬由于未知的原因, 地球 ...

  7. [CTSC1999]【网络流24题】星际转移

    Description 由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177 年冬由于未知的原因,地 ...

  8. 【刷题】LOJ 6015 「网络流 24 题」星际转移

    题目描述 由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了 ...

  9. 【luogu P2245 星际导航】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2245 = 货车运输 被逼着写过mst+lca 后来成了mst+树剖 #include <cstdio& ...

随机推荐

  1. leetcode中Java关于Json处理的依赖

    leetcode的java代码提供的main函数中,往往有关于json的依赖...我找了许久才找到他们用的是这个json实现 <dependency> <groupId>com ...

  2. GO学习-(38) Go语言结构体转map[string]interface{}的若干方法

    结构体转map[string]interface{}的若干方法 本文介绍了Go语言中将结构体转成map[string]interface{}时你需要了解的"坑",也有你需要知道的若 ...

  3. OpenCV 查找轮廓

    本文将结合实例代码,介绍 OpenCV 如何查找轮廓.获取边界框. 代码: contours.py OpenCV 提供了 findContours 函数查找轮廓,需要以二值化图像作为输入.并指定些选项 ...

  4. TensorFlow分布式在Amazon AWS上运行

    TensorFlow分布式在Amazon AWS上运行 Amazon AWS 提供采用 NVIDIA K8 GPU 的 P2.x 机器.为了能够使用,第一步还需要创建一个 Amazon AWS 账户, ...

  5. 相机自动对焦AF原理

    相机自动对焦AF原理 AF性能是判断相机好坏的重要指标,主要从准确度和速度两个方面来进行考察,本文将介绍自动对焦的几种方式. 一.凸透镜成像原理 二.三种对焦方法 有公式在手,只要给相机安个测距仪就好 ...

  6. JMeter使用教程2——MySQL压测

    之前写过一篇JMeter使用教程,只是介绍了http请求的压力测试,想到MySQL的测试也挺必要的,于是写下这篇记录一下.如果不知道怎么下载和安装,可以看一下上一篇关于JMeter的文章,地址是:ht ...

  7. 即时性能分析工具 Pyroscope

    当网站上线后,流量增加或短暂功能故障,都会造成使用者体验相当不好,而这时该怎么快速找到性能的瓶颈呢?通常 CPU 达到 100% 时,有时候也很难复制及找出关键问题点. 本篇文章,我们会介绍一套工具叫 ...

  8. Linux CentOS 配置Yaf框架

    简介 Yaf框架想必大家都有所了解,它是一个开源的高性能的PHP框架 官网地址:https://www.php.net/manual/zh/book.yaf.php Yaf开发文档:https://w ...

  9. 尼恩 Java高并发三部曲 [官方]

    高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三部曲 > 面试必备 + 大厂必备 + 涨薪 ...

  10. C#关于数据库中存储的用户权限类似 "普通员工,管理员" 如何在代码中读取分析权限

    之前在看某些数据库的用户权限的表时,发现字段是这样类似这样存储的"  普通员工,管理员 ",当时觉得他们是通过分割字符串来分析权限的.后来读到 Liam Wang  的 https ...