题目描述

给定平面 x-O-yx−O−y 上 nn 个开线段组成的集合 II ,和一个正整数 kk 。试设计一个算法,从开线段集合 II 中选取出开线段集合 S\subseteq IS⊆I ,使得在 xx 轴上的任何一点 pp ,SS 中与直线 x=px=p 相交的开线段个数不超过 kk ,且\sum\limits_{z\in S}|z|z∈S∑​∣z∣ 达到最大。这样的集合 SS 称为开线段集合 II 的最长 kk 可重线段集。\sum\limits_{z\in S}|z|z∈S∑​∣z∣ 称为最长 kk 可重线段集的长度。

对于任何开线段 zz ,设其断点坐标为 (x_0,y_0)(x0​,y0​) 和 (x_1,y_1)(x1​,y1​) ,则开线段 zz 的长度 |z|∣z∣ 定义为:|z|=\lfloor\sqrt{(x_1-x_0)^2+(y_1-y_0)^2}\rfloor∣z∣=⌊(⌋

对于给定的开线段集合 II 和正整数 kk ,计算开线段集合 II 的最长 kk 可重线段集的长度。

输入输出格式

输入格式:

文件的第一 行有 22 个正整数 nn 和 kk ,分别表示开线段的个数和开线段的可重叠数。

接下来的 nn 行,每行有 44 个整数,表示开线段的 22 个端点坐标。

输出格式:

程序运行结束时,输出计算出的最长 kk 可重线段集的长度。

输入输出样例

输入样例#1: 复制

4 2
1 2 7 3
6 5 8 3
7 8 10 5
9 6 13 9
输出样例#1: 复制

17

说明

1\leq n\leq5001≤n≤500

1 \leq k \leq 131≤k≤13

这题与最长k可重区间集问题本质上是一样的,

但是有一种特殊情况,当这条直线垂直于$y$轴时,我们在连边的过程中会产生负环

怎么办呢?

这里有一个神仙操作

把两个点的$x$值全部*2,若相同,则较小的-1,否则较小的+1

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#include<cmath>
#define int long long
#define AddEdge(x,y,z,f) add_edge(x,y,z,f),add_edge(y,x,-z,0)
using namespace std;
const int MAXN=1e5+;
const int INF=1e8+;
inline int read()
{
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int N,K,S,T;
int anscost=;
struct node
{
int u,v,w,f,nxt;
}edge[MAXN];
int head[MAXN],num=;
inline void add_edge(int x,int y,int z,int f)
{
edge[num].u=x;
edge[num].v=y;
edge[num].w=z;
edge[num].f=f;
edge[num].nxt=head[x];
head[x]=num++;
}
int Pre[MAXN],vis[MAXN],dis[MAXN];
bool SPFA()
{
queue<int>q;
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
dis[S]=;
q.push(S);
while(q.size()!=)
{
int p=q.front();q.pop();
vis[p]=;
for(int i=head[p];i!=-;i=edge[i].nxt)
{
if(dis[edge[i].v]>dis[p]+edge[i].w&&edge[i].f)
{
dis[edge[i].v]=dis[p]+edge[i].w;
Pre[edge[i].v]=i;
if(!vis[edge[i].v])
vis[edge[i].v]=,q.push(edge[i].v);
}
}
}
return dis[T]<=INF;
}
void f()
{
int nowflow=INF;
for(int now=T;now!=S;now=edge[Pre[now]].u)
nowflow=min(nowflow,edge[Pre[now]].f);
for(int now=T;now!=S;now=edge[Pre[now]].u)
edge[Pre[now]].f-=nowflow,
edge[Pre[now]^].f+=nowflow;
anscost+=nowflow*dis[T];
}
void MCMF()
{
int ans=;
while(SPFA())
f();
printf("%lld\n",-anscost);
}
int L[MAXN],R[MAXN],date[MAXN],tot=;
struct Point
{
int xx1,yy1,xx2,yy2,L;
}P[MAXN];
double GetL(int n)
{
return floor((double)sqrt((P[n].xx1-P[n].xx2)*(P[n].xx1-P[n].xx2) + (P[n].yy1-P[n].yy2)*(P[n].yy1-P[n].yy2)));
}
main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
memset(head,-,sizeof(head));
N=read();K=read();
for(int i=;i<=N;i++)
{
P[i].xx1=read(),P[i].yy1=read(),P[i].xx2=read(),P[i].yy2=read();
if(P[i].xx1>P[i].xx2)
swap(P[i].xx1,P[i].xx2),
swap(P[i].yy1,P[i].yy2);
P[i].L=GetL(i);
P[i].xx1*=;
P[i].xx2*=;
if(P[i].xx1==P[i].xx2) P[i].xx1--;
else P[i].xx1++;
date[++tot]=P[i].xx1,date[++tot]=P[i].xx2;
} sort(date+,date+tot+);
int num=unique(date+,date+tot+)-date-;
for(int i=;i<=num-;i++)
AddEdge(i,i+,,INF);
for(int i=;i<=N;i++)
{
P[i].xx1=lower_bound(date+,date+num+,P[i].xx1)-date; P[i].xx2=lower_bound(date+,date+num+,P[i].xx2)-date; AddEdge(P[i].xx1,P[i].xx2,-P[i].L,);
}
S=,T=num*;
AddEdge(S,,,K);
AddEdge(num,T,,K);
MCMF();
return ;
}

最新文章

  1. JavaScript自定义媒体播放器
  2. iOS拨打电话的三种方式
  3. hdu 2073
  4. Android学习笔记(六)
  5. asp.netMVC中,视图层和控制器层的传值
  6. biztalk中使用WCF-SQL接受传送数据【转】
  7. 戴文的Linux内核专题:04安全
  8. VBA Excel 单元格操作
  9. WPF 媒体播放器(MediaElement)使用实例(转)
  10. js 刷新页面大全
  11. OPStackComputeNodeMaintain
  12. Windows I/O模型之一:Select模型
  13. 枚举类型互相转换(使用GetEnumName和TypeInfo两个函数)
  14. ovs + kernel datapath 的分片与重组流程
  15. thinkphp中fetch渲染模板的处理
  16. MariaDB/MySQL备份和恢复(一):mysqldump工具用法详述
  17. [20171031]markhot.txt
  18. spring之hello(简单环境配置)
  19. Element-UI 表格 列过多内容换行问题
  20. uva 1025 A Spy in the Metro 解题报告

热门文章

  1. 搭建 Lepus 天兔 监控MySQL
  2. ASP.NET 微信公众平台模板消息推送功能完整开发
  3. jQuery添加新的元素
  4. 用shell编写一个三角形图案
  5. NOIP2016 天天爱跑步 线段树合并_桶_思维题
  6. 探索JS引擎工作原理 (转)
  7. 【转载】springboot注解
  8. vue v-for下图片src显示失败,404错误
  9. 绘图-CAD-改快捷键
  10. [SharePoint][SharePoint Designer 入门经典]Chapter13 客户端Silverlight编程