网络流24题之最长k可重线段集问题

对于每个线段拆成两个点,如同之前一样建图,由于可能出现垂直于x轴的

所以建图由i指向i~

继续最小费用最大流

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=10000005,inf=1e9;
 4 int head[N],d[N],f[N],l1[N],r1[N],l2[N],r2[N],a[N],s=1e9,t,n,k,cnt=-1;
 5 long long cost;
 6 bool v[N];
 7 struct node{
 8     int to,nex,f,w,c;
 9 }e[1000005];
10 void add(int x,int y,int w,int c)
11 {
12     e[++cnt].to=y;e[cnt].w=w;e[cnt].f=x;e[cnt].c=c;e[cnt].nex=head[x];head[x]=cnt;
13     e[++cnt].to=x;e[cnt].w=0;e[cnt].f=y;e[cnt].c=-c;e[cnt].nex=head[y];head[y]=cnt;
14 }
15 queue<int>q;
16 bool spfa()
17 {
18     memset(f,-1,sizeof(f));
19     memset(d,0x3f,sizeof(d));
20     memset(v,0,sizeof(v));
21     d[s]=0;v[s]=1;q.push(s);
22     while(!q.empty())
23     {
24         int x=q.front();q.pop();v[x]=0;
25         for(int i=head[x];i!=-1;i=e[i].nex)
26         {
27             int y=e[i].to;
28             if(d[y]<=d[x]+e[i].c||!e[i].w)continue;
29
30             d[y]=d[x]+e[i].c;f[y]=i;
31             if(!v[y])q.push(y),v[y]=1;
32         }
33     }
34     if(d[t]>1e9)return 0;
35     int flow=inf;
36     for(int i=f[t];i!=-1;i=f[e[i].f])
37     flow=min(flow,e[i].w);
38     for(int i=f[t];i!=-1;i=f[e[i].f])
39     e[i].w-=flow,e[i^1].w+=flow,cost+=1ll*e[i].c*flow;
40     return 1;
41 }
42 int main()
43 {
44     scanf("%d%d",&n,&k);int num=0;
45     memset(head,-1,sizeof(head));
46     for(int i=1;i<=n;++i)
47     {
48         scanf("%d%d%d%d",&l1[i],&r1[i],&l2[i],&r2[i]);
49         a[++num]=l1[i];a[++num]=l2[i];
50     }
51     sort(a+1,a+1+num);
52     num=unique(a+1,a+1+num)-a-1;
53     for(int i=1;i<=n;++i)
54     {
55         int x=sqrt(1ll*(l1[i]-l2[i])*(l1[i]-l2[i])+1ll*(r2[i]-r1[i])*(r2[i]-r1[i]));
56         l1[i]=lower_bound(a+1,a+1+num,l1[i])-a;
57         l2[i]=lower_bound(a+1,a+1+num,l2[i])-a;
58         if(l1[i]!=l2[i])
59         add((l1[i]<<1)|1,l2[i]<<1,1,-x);
60         else
61         add(l1[i]<<1,(l2[i]<<1)|1,1,-x);
62     }
63     for(int i=1;i<num;++i)
64     {
65         add((i<<1)|1,i+1<<1,inf,0);
66         add(i<<1,(i<<1)|1,inf,0);
67     }
68     add(num<<1,(num<<1)|1,inf,0);
69     t=num*2+10;
70     add((num<<1)|1,t,k,0);
71     add(0,2,k,0);s=0;
72     while(spfa());
73     printf("%lld\n",-cost);
74     return 0;
75 }

原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8400477.html

时间: 2024-10-03 07:57:17

网络流24题之最长k可重线段集问题的相关文章

*LOJ#6227. 「网络流 24 题」最长k可重线段集问题

$n \leq 500$条平面上的线段,问一种挑选方法,使得不存在直线$x=p$与挑选的直线有超过$k$个交点,且选得的直线总长度最长. 横坐标每个点开一个点,一条线段就把对应横坐标连一条容量一费用(-长度)的边:点$x$向点$x+1$连一条容量$k$费用0的边.这里的$k$边限制的是直线上其他不经过这里的地方. 这里有个trick就是有与$x$轴垂直的线段.直接判掉会wa.为此把坐标扩大两倍,如果$l=r$那么$r++$否则$l++$,相当于把一个点拆成两个. 原文地址:https://www

「网络流 24 题」最长 k 可重区间集

给定区间集合$I$和正整数$k$, 计算$I$的最长$k$可重区间集的长度. 区间离散化到$[1,2n]$, $S$与$1$连边$(k,0)$, $i$与$i+1$连边$(k,0)$, $2n$与$T$连边$(k,0)$. 对于每个区间$(l,r)$, $l$与$r$连边$(1,l-r)$. 最小费用相反数就为最大长度 #include <iostream> #include <sstream> #include <algorithm> #include <cst

最长k可重线段集问题

最长k可重线段集问题 时空限制1000ms / 128MB 题目描述 给定平面 x−O−y 上 n 个开线段组成的集合 I,和一个正整数 k .试设计一个算法,从开线段集合 I 中选取出开线段集合 S⊆I ,使得在 x 轴上的任何一点 p,S 中与直线 x=p 相交的开线段个数不超过 k,且∑?∣z∣达到最大.这样的集合 S 称为开线段集合 I 的最长 k 可重线段集.∑?∣z∣ 称为最长 k 可重线段集的长度. 对于任何开线段 z,设其断点坐标为 (x0?,y0?) 和 (x1?,y1?),则

洛谷 P3357 最长k可重线段集问题【最大流】

pre:http://www.cnblogs.com/lokiii/p/8435499.html 和最长k可重区间集问题差不多,也就是价值的计算方法不一样,但是注意这里可能会有x0==x1的情况也就是l==r的情况,然后就TTTTTLE. 其实处理方法很粗暴,因为是开线段,所以可以把它扩大一倍,然后就可以取精度差,对于l!=r,l++,否则l--. 然后正常建模即可. 这个建模大概是用了取补集的思想,把覆盖和没覆盖相转化. #include<iostream> #include<cstd

luogu P3357 最长k可重线段集问题

这题和3358一模一样,建模形式直接不用变,就两点不一样,一是len变化了,加入y后再更新即可,还有就是可能会出现x0=x1的情况,即一条开线段垂直x轴,如果我们依旧按照上一题的建图方法,就会出现负权环,无法跑出答案,我们就可以把一个点拆成入点和出点,这样无论是否是不是垂直都可以一样建,注意开long long,不开long long可能只有9分 #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&(-

【网络流24题】No.21 (最长 k 可重区间集问题 最长不相交路径 最大费用流)

[] 输入文件示例input.txt4 21 76 87 109 13 输出文件示例output.txt15 [分析] 直接co题解好了,写得挺全.. [建模方法] 方法1 按左端点排序所有区间,把每个区间拆分看做两个顶点<i.a><i.b>,建立附加源S汇T,以及附加顶点S'. 1.连接S到S'一条容量为K,费用为0的有向边.2.从S'到每个<i.a>连接一条容量为1,费用为0的有向边.3.从每个<i.b>到T连接一条容量为1,费用为0的有向边.4.从每个

「网络流24题」「LuoguP3358」 最长k可重区间集问题

题目描述 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度. 输入输出格式 输入格式: 的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重迭数.接下来的 n行,每行有 2 个整数,表示开区间的左右端点坐标. 输出格式: 将计算出的最长 k可重区间集的长度输出 输入输出样例 输入样例#1: 复制 4 2 1 7 6 8 7 10 9 13 输出样例#1: 复制 15 说明 对于100%的数据,1<=n<=500,1<=k<

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

Description 给定实直线L 上n 个开区间组成的集合I,和一个正整数k,试设计一个算法,从开区间集合I 中选取出开区间集合S属于I,使得在实直线L 的任何一点x,S 中包含点x 的开区间个数不超过k,且sum(|z|)z属于S,达到最大.这样的集合S称为开区间集合I的最长k可重区间集.sum(|z|) z属于S称为最长k可重区间集的长度.对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度. Solution 1.离散化 然后从每个点i向i+1连一条流量为INF,

【网络流24题】最长不下降子序列(最大流,动态规划)

[网络流24题]最长不下降子序列(最大流,动态规划) 题面 Cogs 题解 很有趣的一道题目 尽管我自己还是有一些懵逼 第一问,直接大力DP一下,不解释了 第二问,考虑到一个长度为ans的子序列的开头 他的dp值一定等于ans, 所以,如果一个点的dp值为ans,就从源点连过去,容量为1 因为每个数只能用一次,因此拆点 自己向自己的新点连容量为1的边 一个子序列的结束的位置其dp值必定为1 所以从dp值为1的新点向汇点连边,容量为1 接下来考虑点与点之间的关系 如果dp[i]=dp[j]+1 并