洛谷P3357 最长k可重线段集问题(费用流)
时间:2022-05-07
本文章向大家介绍洛谷P3357 最长k可重线段集问题(费用流),主要内容包括题目描述http://www.cnblogs.com/zwfymqz/p/8559566.html、输入输出格式、输入输出样例、说明、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
题目描述http://www.cnblogs.com/zwfymqz/p/8559566.html
给定平面 x-O-yx−O−y 上 nn 个开线段组成的集合 II ,和一个正整数 kk 。试设计一个算法,从开线段集合 II 中选取出开线段集合 Ssubseteq IS⊆I ,使得在 xx 轴上的任何一点 pp ,SS 中与直线 x=px=p 相交的开线段个数不超过 kk ,且sumlimits_{zin S}|z|z∈S∑∣z∣ 达到最大。这样的集合 SS 称为开线段集合 II 的最长 kk 可重线段集。sumlimits_{zin S}|z|z∈S∑∣z∣ 称为最长 kk 可重线段集的长度。
对于任何开线段 zz ,设其断点坐标为 (x_0,y_0)(x0,y0) 和 (x_1,y_1)(x1,y1) ,则开线段 zz 的长度 |z|∣z∣ 定义为:|z|=lfloorsqrt{(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
说明
1leq nleq5001≤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+10;
const int INF=1e8+10;
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int N,K,S,T;
int anscost=0;
struct node
{
int u,v,w,f,nxt;
}edge[MAXN];
int head[MAXN],num=2;
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,0,sizeof(vis));
dis[S]=0;
q.push(S);
while(q.size()!=0)
{
int p=q.front();q.pop();
vis[p]=0;
for(int i=head[p];i!=-1;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]=1,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]^1].f+=nowflow;
anscost+=nowflow*dis[T];
}
void MCMF()
{
int ans=0;
while(SPFA())
f();
printf("%lldn",-anscost);
}
int L[MAXN],R[MAXN],date[MAXN],tot=0;
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,-1,sizeof(head));
N=read();K=read();
for(int i=1;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*=2;
P[i].xx2*=2;
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+1,date+tot+1);
int num=unique(date+1,date+tot+1)-date-1;
for(int i=1;i<=num-1;i++)
AddEdge(i,i+1,0,INF);
for(int i=1;i<=N;i++)
{
P[i].xx1=lower_bound(date+1,date+num+1,P[i].xx1)-date;
P[i].xx2=lower_bound(date+1,date+num+1,P[i].xx2)-date;
AddEdge(P[i].xx1,P[i].xx2,-P[i].L,1);
}
S=0,T=num*2;
AddEdge(S,1,0,K);
AddEdge(num,T,0,K);
MCMF();
return 0;
}
- Caliburn.Micro学习笔记(五)----协同IResult
- 一个Pythoner的自我修养系列(一)
- 众里寻她千百度,蓦然回首,那bug却在灯火阑珊处
- Github|Python开源项目漫游指南(一)
- Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能
- .NET 4 System.Threading.CountdownEvent
- java与ruby的直观比较
- 每天一个Linux命令:chmod
- SparkSql 中外连接查询中的谓词下推规则
- Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T>
- Python进行数据可视化分析快速教程实例
- 一个抓取豆瓣图书的开源爬虫的详细步骤
- Java 8 Stream 教程 (三)
- silverlight ListBox 多列图片效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法