P3357 最长k可重线段集问题

题目描述

给定平面 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可重区间集问题是一样的,就是把平面上的线段投影到x轴,但是呢,有一个点有问题,就是要

特判两条直线重合且垂直于x轴的这一种情况,具体是为什么呢,我也有点不明白为什么了,好像是会出现环的情况。

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5;
struct edge
{int u, v, c, f;ll cost;edge(int u, int v, int c, int f, ll cost) :u(u), v(v), c(c), f(f), cost(cost) {}
};
vector<edge>e;
vector<int>G[maxn];
int a[maxn];//找增广路每个点的水流量
int p[maxn];//每次找增广路反向记录路径
int d[maxn];//SPFA算法的最短路
int inq[maxn];//SPFA算法是否在队列中
int s, t;
void init(int n)
{for (int i = 0; i <= n; i++)G[i].clear();e.clear();
}
void add(int u, int v, int c, ll cost)
{e.push_back(edge(u, v, c, 0, cost));e.push_back(edge(v, u, 0, 0, -cost));int m = e.size();G[u].push_back(m - 2);G[v].push_back(m - 1);
}
bool bellman(int s, int t, int& flow, long long & cost)
{memset(d, 0xef, sizeof(d));memset(inq, 0, sizeof(inq));d[s] = 0; inq[s] = 1;//源点s的距离设为0,标记入队p[s] = 0; a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的)
queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
    q.push(s);while (!q.empty()){int u = q.front();q.pop();inq[u] = 0;//入队列标记删除for (int i = 0; i < G[u].size(); i++){edge & now = e[G[u][i]];int v = now.v;if (now.c > now.f && d[v] < d[u] + now.cost)//now.c > now.f表示这条路还未流满(和最大流一样)//d[v] > d[u] + e.cost Bellman 算法中边的松弛
            {d[v] = d[u] + now.cost;//Bellman 算法边的松弛p[v] = G[u][i];//反向记录边的编号a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量if (!inq[v]) { q.push(v); inq[v] = 1; }//Bellman 算法入队
            }}}if (d[t] < 0)return false;//找不到增广路flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flowcost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用for (int u = t; u != s; u = e[p[u]].u)//逆向存边
    {e[p[u]].f += a[t];//正向边加上流量e[p[u] ^ 1].f -= a[t];//反向边减去流量 (和增广路算法一样)
    }return true;
}
int MaxcostMaxflow(int s, int t, long long & cost)
{cost = 0;int flow = 0;while (bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和costreturn flow;//返回最大流,cost引用可以直接返回最小费用
}struct node
{int xx1, yy1, xx2, yy2;ll cost;
}exa[maxn];
bool cmp(node a, node b)
{return a.xx1 < b.xx1;
}ll dis(int x, int y, int x1, int y1)
{return sqrt((x - x1) * 1ll * (x - x1) + (y - y1) * 1ll * (y - y1));
}int main()
{int n, m;cin >> n >> m;int s1 = 1;s = 0, t = 2 * n + 3;for (int i = 1; i <= n; i++){cin >> exa[i].xx1 >> exa[i].yy1 >> exa[i].xx2 >> exa[i].yy2;if (exa[i].xx1 > exa[i].xx2){swap(exa[i].xx1, exa[i].xx2);swap(exa[i].yy1, exa[i].yy2);}exa[i].cost = dis(exa[i].xx1, exa[i].yy1, exa[i].xx2, exa[i].yy2);}sort(exa + 1, exa + 1 + n, cmp);add(s, s1, m, 0);for (int i = 1; i <= n; i++){add(s1, 1 + 2 * i - 1, 1, 0);add(1 + 2 * i - 1, 1 + 2 * i, 1, exa[i].cost);add(1 + 2 * i, t, 1, 0);for (int j = 1; j < i; j++){if (exa[j].xx2 == exa[i].xx1&&exa[j].xx1 == exa[j].xx2&&exa[i].xx1==exa[i].xx2) continue;if (exa[j].xx2 <= exa[i].xx1) add(1 + 2 * j, 1 + 2 * i - 1, 1, 0);}}ll cost = 0;int ans = MaxcostMaxflow(s, t, cost);printf("%lld\n", cost);return 0;
}

转载于:https://www.cnblogs.com/EchoZQN/p/10792823.html

P3357 最长k可重线段集问题 网络流相关推荐

  1. P3357 最长k可重线段集问题(网络流/串联/拆点)

    P3357 最长k可重线段集问题 对于n条开线段,选择一个子集使得任意x=p和子集相交的直线个数小于等于k,并使得选择的线段长度之和最大. 这道题看上去和区间集没有什么区别,只是费用发生变化,但是要注 ...

  2. 洛谷 - P3357 最长k可重线段集问题(最大费用最大流+思维建边+拆点)

    题目链接:点击查看 题目大意:给出n条开线段,开线段的意思就是端点的两个点属于开区间,不属于线段中,让从中选出数条线段,满足: 在x轴选取任何一个点,选取线段向x轴映射到该点的次数小于等于k 所选线段 ...

  3. 洛谷P3357:最长k可重线段集问题(网络流)

    解析 本题的建模方法有很多,我的做法是补集思想转化成志愿者招募然后按照那道题的做法直接做,看题解更多是采用的对于不冲突的线段首尾加边的做法. 在前一道最长k可重区间问题中这两种做法谈不上孰优孰劣,但本 ...

  4. 最长k可重区间集问题最长k可重线段集问题

    题解: 洛谷上这两题的题意都是有问题的 按照标程题意不应该是开区间而是左开右闭区间 然后连边比较巧妙 我们可以看成选k条不相交的路径,其中i-i+1中有k条边 所以建图i-i+1流量为k,权值为0 l ...

  5. 【刷题】LOJ 6014 「网络流 24 题」最长 k 可重区间集

    题目描述 给定实直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取出开区间集合 \(S \subseteq ...

  6. P3358 最长k可重区间集问题(网络流:串联思想)

    P3358 最长k可重区间集问题 这是一个经典模型,给定n个开区间,选择一些区间使得每个位置被覆盖次数不超过k,并最大化选择的区间长度之和. 首先一个直接的想法就是每一个区间匹配了它所对应的点,但是我 ...

  7. 洛谷 - P3358 最长k可重区间集问题(最大费用最大流+思维建边)

    题目链接:点击查看 题目大意:给出n个开区间,现在要求从中选取一定数量的区间,需要满足: 对于任意点x,所选取的区间中包含点x的个数小于等于k 区间长度和最大 要求输出最长的区间长度和 题目分析:一开 ...

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

    对于区间 u->v ,连接边 u->v,权值为-len,容量为1,之后对每个点 i->i+1,连边 i->i+1,容量为k,权值为0,求区间最左端点到最右端点的费用流,费用相反 ...

  9. 网络流24题之最长k可重区间集问题

    对于每个点向后一个点连流量为k费用为0的边 对每一区间连l到r流量为1费用为r-l的边 然后最小费用最大流,输出取反 一开始写的r-l+1错了半天... By:大奕哥 1 #include<bi ...

最新文章

  1. R可视化多元线性回归模型
  2. Redhate5.4下Oracle 11g安装
  3. 计算机网络的OSI七层模型
  4. python去重且顺序不变_Python中list去重且保持原顺序不变的方法
  5. Linux 基本权限管理
  6. IoT:BLE4.0教程一 蓝牙协议连接过程与广播分析
  7. 关于vhr项目部署所遇到的问题总结,Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin
  8. Mac安装numpy
  9. 常见AutoCAD病毒(acad.fas、acad.lsp)清除方法
  10. python语料库_Python-使用NLTK创建新的语料库
  11. 威金杀虫剂作者农夫和威金病毒制造者的聊天记录
  12. ORACLE EBS 启用REST服务-1-环境安装篇
  13. 蚂蚁迷宫—有限状态机设计(ANT MAZE)
  14. MFC__ZPL语言Zbor打印机打印数据换行问题
  15. Android memery data sample
  16. 深入浅出Zookeeper集群搭建
  17. 将图像平移到画布中心python_python前端之Photoshop
  18. matlab自动生成excel工作区,matlab数据怎么导出excel表格-matlab工作区数据怎么转为excel...
  19. 雨林木风诚聘Linux研发工程师
  20. 小米会成为三星没落的因素吗?

热门文章

  1. el-table数据不显示_数据透视表,一篇就够了
  2. 批量删除html网页,批量删除.html · panghuamama/Clearly Local - Gitee.com
  3. python 图片转视频ffmpeg_python图片转视频(opencv),ffmpeg压缩视频
  4. mysql主从架构升级_实战项目——mysql主从架构的实现
  5. 单路电压表c语言编程,用AT89C51单片机制作的数字电压表
  6. 宝塔添加多占点_宝塔面板启用WordPress多站点子域名、子目录
  7. Linux入门笔记——type、switch、help、man、apropos、whatis、info
  8. 破解key file时经常用到的几个API函数及其用法
  9. c语言条件语句示例_PHP中的条件语句和示例
  10. 前序遍历m-ary树_在Ruby中使用ary [start,length]- object进行数组元素分配