最长 \(k\) 可重线段集

题目大意

给定平面 \(x-O-y\) 上 \(n\) 个开线段组成的集合 \(I\) ,和一个正整数 \(k\) 。试设计一个算法,从开线段集合 \(I\) 中选取开线段集合 \(S \subseteq I\) ,使得在 \(x\) 轴上的任意一点 \(P\) , \(S\) 中与直线 \(x=p\) 相交的开线段个数不超过 \(k\) ,且 \(\sum_{z \in S}|z|\) 最大。这样的集合 \(S\) 称为开线段集合 \(I\) 的最长 \(k\) 可重线段集。 \(\sum_{z\in S}|z|\) 称为最长 \(k\) 可重线段集的长度。

对于任意开线段 \(z\) ,设其端点坐标为 \((x_0,y_0)\) 和 \((x_1,y_1)\) ,则开线段 \(z\) 的长度 \(|z|\) 定义为:

\[|z|=[\sqrt{(x_1-x_0)^2+(y_1-y_0)^2}]
\]

对于给定的开线段集合 \(I\) 和正整数 \(k\) ,计算开线段集合 \(I\) 的最长 \(k\) 可重线段集的长度。

分析

想要解决此题,可以先看一下与该题基本如出一辙的:最长 \(k\) 可重区间集[题解]

其实这道题和上述此题非常类似,只不过将水平的区间转化为了一些基本无规律处于二维平面内的线段。

那么我们还是可以把问题转化到 \(x\) 上,我们发现其实 \(y\) 坐标和题目的限制关系不大,我们只需要解决横坐标部分即可。

其实我们只需要把线段两个端点的 \(x\) 坐标转化为何上述题目一样的区间即可,就可以得到和上述题目一样的过程,具体分析可以点击上方链接,下面直接给出建图思路:

  • 将每个线段的左右端点的 \(x\) 坐标储存起来,并将线段 \(i\) 拆成 \(i\) 与 \(i'\) 分别表示点 \(i\) 的入点与出点,对于每对拆点,在他们中间连接一条流量为 \(1\) ,费用为线段长度的边。

  • 建立一个超级源点超级汇点,超级源点向真正的源点连接一条流量为 \(k\) ,费用为 \(0\) 的边,并再将源点向每条线段的入点连接一条流量为 \(1\) ,费用为 \(0\) 的边,每条线段的出点向超级汇点连接一条流量为 \(1\) ,费用为 \(0\) 的边。

  • 对于左右端点形成的区间互不相交的线段,在他们之间建立一条流量为 \(+\infty\) ,费用为 \(0\) 的边。

这样就可以直接跑最大费用了。

需要注意两个地方:

  • 本文一开始的链接中详细论述了线段连接有序性的必要,所以我们必须要排序或是要保证线段连接的有序。

  • 对于两条线段,如果他们完全相同的话,我们仍然需要将其计算在限制内,所以需要进行特殊判断,不能进行连边。

最后代码如下:

CODE

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e2+10,INF=0x7fffffff;
int n,k,s,t,_s,ans;
struct node{ int l,r,len; }sec[N];
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;
}
inline bool cmp(node x,node y) { return x.l<y.l; }
int tot=-1,v[2*N*N],w[2*N*N],pay[2*N*N],nex[2*N*N],first[2*N];
inline void Add(int x,int y,int z,int c)
{
nex[++tot]=first[x];
first[x]=tot;
v[tot]=y,w[tot]=z,pay[tot]=c;
}
bool vis[2*N];
int pre[2*N],dis[2*N],Min[2*N];
inline bool SPFA()
{
for(register int i=s;i<=t;i++) dis[i]=-INF;
for(register int i=s;i<=t;i++) vis[i]=false;
queue<int> q;
q.push(s);
vis[s]=true,dis[s]=0,Min[s]=INF;
while(!q.empty()){
int now=q.front(); q.pop();
vis[now]=false;
for(register int i=first[now];i!=-1;i=nex[i]){
int to=v[i];
if(!w[i]) continue;
if(dis[to]<dis[now]+pay[i]){
dis[to]=dis[now]+pay[i];
Min[to]=min(Min[now],w[i]);
pre[to]=i;
if(!vis[to]) q.push(to),vis[to]=true;
}
}
}
return dis[t]!=-INF;
}
inline void EK()
{
while(SPFA()){
ans+=Min[t]*dis[t];
int temp=t,i;
while(temp!=s){
i=pre[temp];
w[i]-=Min[t];
w[i^1]+=Min[t];
temp=v[i^1];
}
}
}
signed main()
{
memset(first,-1,sizeof(first));
n=read(),k=read();
for(register int i=1;i<=n;i++){
int _x1=read(),_y1=read(),_x2=read(),_y2=read();
sec[i].l=min(_x1,_x2),sec[i].r=max(_x1,_x2);
sec[i].len=(int)sqrt((_x1-_x2)*(_x1-_x2)+(_y1-_y2)*(_y1-_y2));
}
s=0,_s=2*n+1,t=2*n+2;
sort(sec+1,sec+n+1,cmp);
Add(s,_s,k,0),Add(_s,s,0,0);
for(register int i=1;i<=n;i++){
Add(_s,i,1,0),Add(i,_s,0,0);
Add(i,i+n,1,sec[i].len),Add(i+n,i,0,-sec[i].len);
Add(i+n,t,1,0),Add(t,i+n,0,0);
}
for(register int i=1;i<=n;i++){
for(register int j=i+1;j<=n;j++){
if(sec[i].l==sec[i].r&&sec[j].l==sec[j].r&&sec[i].l==sec[j].l) continue;
if(sec[j].l>=sec[i].r||sec[i].l>=sec[j].r) Add(i+n,j,INF,0),Add(j,i+n,0,0);
}
}
EK();
printf("%lld\n",ans);
return 0;
}

[网络流24题]最长k可重线段集[题解]的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 【网络流24题】最长k可重线段集(费用流)

    [网络流24题]最长k可重线段集(费用流) 题面 Cogs的数据有问题 Loj 洛谷 题解 这道题和最长k可重区间集没有区别 只不过费用额外计算一下 但是,还是有一点要注意的地方 这里可以是一条垂直的 ...

  9. 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题

    题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...

随机推荐

  1. C语言编译器开发之旅(一):词法分析扫描器

    本节我们先从一个简易的可以识别四则运算和整数值的词法分析扫描器开始.它实现的功能也很简单,就是读取我们给定的文件,并识别出文件中的token将其输出. 这个简易的扫描器支持的词法元素只有五个: 四个基 ...

  2. 痞子衡嵌入式:改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常. 痞子衡的嵌入式技术交流群里有一位非常活跃的朋友(网名:文 ...

  3. Java | Stream流、泛型、多线程 | 整理自用

    1.lambda 表达式 lambda 的延迟执行 可以对程序进行优化,尤其是使用 if {} else {} 条件判断,先判断条件是否成立,再传入计算好的参数. functionName( para ...

  4. 回文词——线性dp

    #include<iostream> #include<cstdio> using namespace std; int n,f[5002][5002]; char str1[ ...

  5. QT绘制简易表盘

    1.简介 最近学习了一下QT,熟悉了一段时间后发现它的功能还是挺强大的,同时也比较方便用户上手去使用.现在就基于最近学习的内容,实现一个简易的带指针旋转功能的表盘.文中表盘的实现是基于QT的QPain ...

  6. ICCV2019论文点评:3D Object Detect疏密度点云三维目标检测

    ICCV2019论文点评:3D Object Detect疏密度点云三维目标检测 STD: Sparse-to-Dense 3D Object Detector for Point Cloud 论文链 ...

  7. 初具雏形的UL标准侧重于自主车辆的安全性

    初具雏形的UL标准侧重于自主车辆的安全性 Nascent UL standard focuses on autonomous vehicle safety 就任何自主汽车(AV)的安全性进行可信的争论 ...

  8. https ssl(tls)为什么不直接用公钥加密数据?

    很多人都提到了非对称加密速度慢,但这只是一个原因,但不是主要原因,甚至是微不足道的原因. SSL协议到3.0后就已经到头了,取而代之的是TLS,相较于SSL的"安全套接字层"的命名 ...

  9. 实用的jar包加密方案

    前言 jar包相信大家都很熟悉,是通过打包java工程而获得的产物,但是jar包是有一个致命的缺点的,那就是很容易被反编译,只需要使用jd-gui就可以很容易的获取到java源码. 如果你想要防止别人 ...

  10. Python字符与字节新编

    字符 字符是一个信息单位,简单来讲就是一个字母.数字.标点符号.汉字等. 字符的最佳定义是Unicode字符: 它是一个全球化的标准,能表示世界上所有语言的字符.Unicode字符的标识(码位)是以4 ...