网络流24题:最长 k 可重区间集问题题解
最长 k 可重区间集问题题解:
突然想起这个锅还没补,于是来把这里补一下qwq。
1.题意简述:
有\(n\)个开区间,这\(n\)个开区间组成了一个直线\(L\),要求选择一些区间,使得在直线\(L\)上的任意一点,对于你选择的区间来说,包含这个点的区间个数不超过$k $,且满足区间长度和最大。
2.要点:
因为是开区间,所以长度为\(r-l\)
所用算法为\(EK\)费用流
3.\(solution1 :\)
首先让我们思考这个过程,我们要选择一些区间,那么限制条件是得给在区间上的。考虑这么一种情况,就是有两个区间互不相交。
这种情况对这两个区间互相之间是不影响的,也就是说这两个区间是可以一起选的。换成网络流考虑,这两个区间是可以连边的。
然后考虑怎么连边,我们发现这道题的连边极其复杂,我们要考虑这些区间的长度,也就是每个区间对应的权值。
如果这个当为点权的话是不好计算的,那么我们就尝试拆点,把区间给拆开,然后把点权当成边权来计算。
照样是将一个点\(x\)拆成入点\(x\)和出点\(x+N\)因为一个区间只能选择\(1\)次,那么,我们给每个点对应的入点和出点之间连接一条流量为1,费用为区间长度的边。这样我们就完成了对与区间点权的转化,把他转化成了边权。
那么我们说到,像上图中那样是可以同时选的,因为这两个点之间不影响,但是具体选不选呢?这得看后面不选这个是否更优。于是,只要满足这两个区间之间没有交,这两个区间之内就可以连边。
然后就是考虑对于每个点只能被\(k\)个点覆盖这个限制,这个限制怎么办?这个限制换一种说法,永远不会选择\(k\)个以上交于一点的区间。每个点被覆盖当且仅当线段的起点或者说是终点被覆盖。
我们把区间抽象成立一条条线段。
然后按着线段的集合进行分层,每一层中的线段是互不相交的
那么最多只能叠上\(k\)层,为什么呢?因为每一层中线段是互不相交的,那么后一层一定与前面的线段有相交。然后找到第\(k\)层的时候,得到的收益一定最大。
那么就对于跑\(k\)次的限制来吧,可以在加一个附加源点进行限流,设定流量为\(k\),然后用这个点去和每个入点进行连接。这样为什么是对的呢?因为,你发现一件事,你之前连的边之中就是连接的互不相交的边,那么这么来,对于每一个点来说,你就是一层,然后当你跑完后,那么得到的答案即为最大。
(思路有点乱,建议自己理理
那么建模是这样的:
- 建立一个超级源点\(s\),在建立一颗附加源点\(S\),中间连费用为\(0\),流量为\(k\)的边。
- 附加源点\(S\)向每一个入点连一条流量为\(1\),费用为\(0\)的边
- 每个入点向自己的出点连一条流量为\(1\),费用为区间长度的边
- 对于每一个区间,找到一个与它不重的区间,他们之间连一条流量为\(INF\),费用为\(0\)的边。
- 建立一个超级汇点\(t\),每一个出点向超级汇点连接一条流量为\(1\),费用为\(0\)的边。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
template<typename T> inline void read(T &x){
T f=1;x=0;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
const int N = 4e5,INF=2e9;
int n,k;
struct query{
int l,r;
}a[N];
bool cmp(query x,query y){
return x.l<y.l;
}
int nex[N],first[N],v[N],num=1,flow[N],cost[N],pre[N];
void add(int from,int to,int val,int c){
nex[++num]=first[from];
first[from]=num;
v[num]=to;
flow[num]=val;
cost[num]=c;
}
int dis[N],vis[N],inf[N],q[N],last[N],mincost;
bool spfa(int s,int t){
memset(dis,0xcf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(inf,0x7f,sizeof(inf));
q[1]=s;
vis[s]=1;
dis[s]=0;
pre[t]=-1;
int l=0,r=1;
while(l!=r){
int u=q[++l];
vis[u]=0;
for(int i=first[u];i;i=nex[i]){
int to=v[i];
if(flow[i] && dis[to]<dis[u]+cost[i]){
dis[to]=dis[u]+cost[i];
pre[to]=u;
last[to]=i;
inf[to]=min(inf[u],flow[i]);
if(!vis[to]){
vis[to]=1;
q[++r]=to;
}
}
}
}
return pre[t]!=-1;
}
void EK(int s,int t){
while(spfa(s,t)){
int now=t;
mincost+=inf[t]*dis[t];
while(now!=s){
flow[last[now]]-=inf[t];
flow[last[now]^1]+=inf[t];
now=pre[now];
}
}
}
int s,t,S;
signed main(){
read(n),read(k);
for(int i=1;i<=n;i++){
read(a[i].l),read(a[i].r);
if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
}
s=0;
S=4*n;
t=5*n;
add(s,S,k,0);
add(S,s,0,0);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
add(S,i,1,0);
add(i,S,0,0);
add(i,i+n,1,a[i].r-a[i].l);
add(i+n,i,0,a[i].l-a[i].r);
add(i+n,t,1,0);
add(t,i+n,0,0);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[j].l>=a[i].r||a[i].l>=a[j].r){
add(i+n,j,INF,0);
add(j,i+n,0,0);
}
}
}
EK(s,t);
cout<<mincost;
return 0;
}
4.$solution2:\ $
这里有网上的另一种做法,效果更加优异,但是我觉得怪怪的,反正我是没有直接想出来。但是这种做法的复杂度更优,我有空再补把。
这里把几篇讲得看起来很详细得题解拿过来,如果想学习得去看这个把。
太难为我了,完结了QAQ。
网络流24题:最长 k 可重区间集问题题解的更多相关文章
- COGS743. [网络流24题] 最长k可重区间集
743. [网络流24题] 最长k可重区间集 ★★★ 输入文件:interv.in 输出文件:interv.out 简单对比时间限制:1 s 内存限制:128 MB «问题描述: «编 ...
- [网络流24题]最长k可重区间集[题解]
最长 \(k\) 可重区间集 题目大意 给定实心直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取开区间集 ...
- [网络流24题] 最长k可重区间集
https://www.luogu.org/problemnew/show/3358 以区间(1,5),(2,6),(7,8)为例 建模方法一: 建模方法二: 离散化区间端点 相当于找k条费用最大的不 ...
- [网络流24题] 最长K可重区间集问题
题目链接:戳我 当时刷24题的时候偷了懒,没有写完,结果落下这道题没有写qwq结果今天考试T3中就有一部分要用到这个思想,蒟蒻我硬是没有想到网络流呜呜呜 最大费用流. 就是我们考虑将问题转化一下,转化 ...
- [网络流24题] 最长k可重区间集问题 (费用流)
洛谷传送门 LOJ传送门 很巧妙的建图啊...刚了$1h$也没想出来,最后看的题解 发现这道题并不类似于我们平时做的网络流题,它是在序列上的,且很难建出来二分图的形. 那就让它在序列上待着吧= = 对 ...
- [网络流24题]最长k可重线段集[题解]
最长 \(k\) 可重线段集 题目大意 给定平面 \(x-O-y\) 上 \(n\) 个开线段组成的集合 \(I\) ,和一个正整数 \(k\) .试设计一个算法,从开线段集合 \(I\) 中选取开线 ...
- [网络流24题] 最长k可重线段集问题 (费用流)
洛谷传送门 LOJ传送门 最长k可重区间集问题的加强版 大体思路都一样的,不再赘述,但有一些细节需要注意 首先,坐标有负数,而且需要开$longlong$算距离 但下面才是重点: 我们把问题放到了二维 ...
- 网络流24题-最长k可重线段集问题
最长k可重线段集问题 时空限制1000ms / 128MB 题目描述 给定平面 x−O−y 上 n 个开线段组成的集合 I,和一个正整数 k .试设计一个算法,从开线段集合 I 中选取出开线段集合 S ...
- 【网络流24题】最长k可重区间集(费用流)
[网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...
随机推荐
- Go语言流程控制03--goto跳转到任意标签位置
package main import ( "fmt" "time" ) func main() { STUDYHARD: fmt.Println(" ...
- 转载 | Scala 如何避免使用 Null
在 Java 里,null 是一个关键字,不是一个对象,所以对它调用任何方法都是非法的. Scala 的 Option类型 Scala在变量和函数返回值可能不会引用任何值的时候使用 Option 类型 ...
- 原子层沉积(ALD)和化学气相沉积(CVD)微电子制造铜金属化的研究进展
原子层沉积(ALD)和化学气相沉积(CVD)微电子制造铜金属化的研究进展 Atomic Layer Deposition (ALD) and Chemical Vapor Deposition (CV ...
- 打造住院新体验,GVS智慧病房有何独到之处?
3月26-28日,由广东省医院协会主办的"2021第二届广东省医院建设大会暨医院建筑与装备展览会"在广州琶洲国际采购中心盛大举办,来自全国各地的医院代表及企事业单位代表4000余人 ...
- 10分钟用JS实现微信 "炸屎"大作战
大家好,我是秋风,近日,微信又发布了新功能(更新到微信8.0.6).最火热的非"炸屎"功能莫属了,各种群里纷纷玩起了炸屎的功能. 不知道大家是否经历过那样一个时候,小时候(我是说很 ...
- 【工具解析】瑞士军刀bettercap2.X解析_第一期_编写HTTP代理注入模块_http(s).proxy.script
/文章作者:Kali_MG1937 CNBLOG博客号:ALDYS4 QQ:3496925334/ 前言 bettercap已经从1.6更新至2.0版本 语言也从ruby改为了go 编写注入模块指定的 ...
- 【Android编程】Java利用Socket类编写Metasploit安卓载荷辅助模块
/作者:Kali_MG1937 CSDN博客:ALDYS4 QQ:3496925334/ 注意!此文章被作者标记到 黑历史 专栏中,这意味着本篇文章可能存在 质量低下,流水账文,笔法低质 的问题 为了 ...
- InnoDB 静态数据加密的常见问题合集
1. 数据是否为有权查看数据的用户解密? 是的.InnoDB静态数据加密旨在透明地在数据库中应用加密,而不会影响现有应用程序.以加密格式返回数据会破坏大多数现有应用程序. InnoDB静态数据加密提供 ...
- 【NX二次开发】创建有界平面UF_MODL_create_bplane
先准备几条曲线如下图所示,我们用这几条线来创建一个有界平面: 效果: 源码: //有界平面 extern DllExport void ufusr(char *param, int *returnC ...
- 有效Ajax案例
<script>$(document).ready(function(){ $("input:submit").click(function(){ $.ajax({ t ...