最长 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\),然后用这个点去和每个入点进行连接。这样为什么是对的呢?因为,你发现一件事,你之前连的边之中就是连接的互不相交的边,那么这么来,对于每一个点来说,你就是一层,然后当你跑完后,那么得到的答案即为最大。

(思路有点乱,建议自己理理

那么建模是这样的:

  1. 建立一个超级源点\(s\),在建立一颗附加源点\(S\),中间连费用为\(0\),流量为\(k\)的边。
  2. 附加源点\(S\)向每一个入点连一条流量为\(1\),费用为\(0\)的边
  3. 每个入点向自己的出点连一条流量为\(1\),费用为区间长度的边
  4. 对于每一个区间,找到一个与它不重的区间,他们之间连一条流量为\(INF\),费用为\(0\)的边。
  5. 建立一个超级汇点\(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:\ $

这里有网上的另一种做法,效果更加优异,但是我觉得怪怪的,反正我是没有直接想出来。但是这种做法的复杂度更优,我有空再补把。

这里把几篇讲得看起来很详细得题解拿过来,如果想学习得去看这个把。

1号大佬博客

2号大佬博客

花姐姐的博客

太难为我了,完结了QAQ。

网络流24题:最长 k 可重区间集问题题解的更多相关文章

  1. COGS743. [网络流24题] 最长k可重区间集

    743. [网络流24题] 最长k可重区间集 ★★★   输入文件:interv.in   输出文件:interv.out   简单对比时间限制:1 s   内存限制:128 MB «问题描述: «编 ...

  2. [网络流24题]最长k可重区间集[题解]

    最长 \(k\) 可重区间集 题目大意 给定实心直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取开区间集 ...

  3. [网络流24题] 最长k可重区间集

    https://www.luogu.org/problemnew/show/3358 以区间(1,5),(2,6),(7,8)为例 建模方法一: 建模方法二: 离散化区间端点 相当于找k条费用最大的不 ...

  4. [网络流24题] 最长K可重区间集问题

    题目链接:戳我 当时刷24题的时候偷了懒,没有写完,结果落下这道题没有写qwq结果今天考试T3中就有一部分要用到这个思想,蒟蒻我硬是没有想到网络流呜呜呜 最大费用流. 就是我们考虑将问题转化一下,转化 ...

  5. [网络流24题] 最长k可重区间集问题 (费用流)

    洛谷传送门 LOJ传送门 很巧妙的建图啊...刚了$1h$也没想出来,最后看的题解 发现这道题并不类似于我们平时做的网络流题,它是在序列上的,且很难建出来二分图的形. 那就让它在序列上待着吧= = 对 ...

  6. [网络流24题]最长k可重线段集[题解]

    最长 \(k\) 可重线段集 题目大意 给定平面 \(x-O-y\) 上 \(n\) 个开线段组成的集合 \(I\) ,和一个正整数 \(k\) .试设计一个算法,从开线段集合 \(I\) 中选取开线 ...

  7. [网络流24题] 最长k可重线段集问题 (费用流)

    洛谷传送门 LOJ传送门 最长k可重区间集问题的加强版 大体思路都一样的,不再赘述,但有一些细节需要注意 首先,坐标有负数,而且需要开$longlong$算距离 但下面才是重点: 我们把问题放到了二维 ...

  8. 网络流24题-最长k可重线段集问题

    最长k可重线段集问题 时空限制1000ms / 128MB 题目描述 给定平面 x−O−y 上 n 个开线段组成的集合 I,和一个正整数 k .试设计一个算法,从开线段集合 I 中选取出开线段集合 S ...

  9. 【网络流24题】最长k可重区间集(费用流)

    [网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...

随机推荐

  1. GO学习-(33) Go实现日志收集系统2

    Go实现日志收集系统2   一篇文章主要是关于整体架构以及用到的软件的一些介绍,这一篇文章是对各个软件的使用介绍,当然这里主要是关于架构中我们agent的实现用到的内容 关于zookeeper+kaf ...

  2. Python+Selenium学习笔记14 - python官网的tutorial - just() fill() format()

    repr(x).rjust(n)  左侧空格填充,右侧列对齐,str()和repr()是一种输出,也可不用,直接x.rjust() repr(x).ljust(n)  右侧空格填充,左侧列对齐 rep ...

  3. TVM性能评估分析(三)

    TVM性能评估分析(三) Figure 1. TVM's WebGPU backend close to native GPU performance when deploying models to ...

  4. Tensor基础实践

    Tensor基础实践 飞桨(PaddlePaddle,以下简称Paddle)和其他深度学习框架一样,使用Tensor来表示数据,在神经网络中传递的数据均为Tensor. Tensor可以将其理解为多维 ...

  5. JSP三大指令是什么?

    JSP页面中的指令JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言等.语法规则:<%@ 指令名 属性=值 属性=值 ... %>指令可以有很多个属性,它们以键值对的形 ...

  6. PageHelper--Mybatis分页插件(ssm框架下的使用)

    1.导入PageHelper依赖 <!-- MyBatis 分页插件 --> <dependency> <groupId>com.github.pagehelper ...

  7. SQL注入问题------JDBC编写简单登录代码

    一.什么是sql注入 sql注入:用户输入的内容, 有一些sql的特殊关键字参与字符串的拼接,完成了一条逻辑发生变化的新的SQL语句 !用代码举个例子简单说明一下: package cn.zhbit. ...

  8. 使用Flutter设计一个好看的"我"页面

    近期遇到一些很烦的琐事,状态比较down,很多原本计划好的事情都耽搁了,实在是难顶-- 看到后台一直有朋友问怎么博客和公众号没有更新,所以我忙完得闲就来更了! 前言 起因是最近重拾以前的旧项目(业余做 ...

  9. 《手把手教你》系列基础篇之(一)-java+ selenium自动化测试-环境搭建(上)(详细教程)

    1.简介 jmeter系列的文章结束,本来想趁热打铁顺别将Jmeter和接口测试介绍一下,但是感觉Jmeter时间太长了怕大家吃腻了,还有一个原因就是许多小伙伴们或者童鞋们私信问宏哥什么时候可以有ja ...

  10. 剖析虚幻渲染体系(06)- UE5特辑Part 1(特性和Nanite)

    目录 6.1 本篇概述 6.1.1 本篇内容 6.1.2 基础概念 6.2 UE5新特性 6.2.1 UE5编辑器 6.2.1.1 下载编辑器及资源 6.2.1.2 启动示例工程 6.2.1.3 编辑 ...