最长 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. Linux-SSH介绍与认证方式

    Linux SSH 前言: 在实际的生产环境中,运维人员经常要使用本地的计算机对远程主机进行控制工作,TCP/IP协议提供了两种协议来完成这样的操作,分别为Telnet协议和SSH协议. 由于Teln ...

  2. 编译原理-DFA与正规式的转化

  3. Jmeter-逻辑控制器If Controller的实例运用

    一.If Controller概述 Expression (must evaluate to true or false) :表达式(值必须是true或false),也就是说,在右边文本框中输入的条件 ...

  4. 三、部署被监控主机-Zabbix Agent

    三.部署被监控主机-Zabbix Agent 1) 源码安装Zabbix agent软件 在2.100和2.200做相同操作(以zabbixclient web1为例). [root@zabbixcl ...

  5. 【C++】秒级时间戳,毫秒级时间戳

    时间戳,秒级 测试代码: #include <iostream> #include <time.h> #include <windows.h> using name ...

  6. 【NX二次开发】Block UI 多行字符串

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  7. 【NX二次开发】Block UI 从列表选择部件

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  8. NX二次开发-通过数组创建矩阵

    函数:UF_CSYS_create_matrix() 函数说明:通过数组创建矩阵. 用法: #include <uf.h> #include <uf_csys.h> exter ...

  9. cmd快捷键设置

    操作系统:windows7 x64 目的:像在任意空白处右键都有新建文档的功能一样,将cmd添加到右键里. 操作:百度经验 http://jingyan.baidu.com/article/948f5 ...

  10. spring boot使用@Async异步注解

    1.java的大部分接口的方法都是串行执行的,但是有些业务场景是不需要同步返回结果的,可以把结果直接返回,具体业务异步执行,也有些业务接口是需要并行获取数据,最后把数据聚合在统一返回给前端. 通常我们 ...