P3358 最长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\le n\le 5001≤n≤500,1\le k\le 31≤k≤3

写一下这个题目的思路,这个图很难建。
看了一下题解,觉得很巧妙。

看了这个图就好理解一点了,就是你要把k假定为网络流的最大流量,把每一个区间离散化。

这个看代码更好理解一些,不过可以抽象的讲一下。

就是你把这些区间互不相重叠的划成一条路,假设有5条路,k=2,

那么最多只能从这五条路里面选择两条路,因为如果大于等于2,那么就会出现问题,比如说,第一个区间和第二个区间,

则第二个区间里的每一段,如果不是和第一个区间肯定都是和第一个区间的某一段有交集。

。。。。不好说,还是看代码吧,多搜搜题解,不放弃,最后总会写的。

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#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, cost;
edge(int u, int v, int c, int f, int 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 = ; i <= n; i++)G[i].clear();
e.clear();
}
void add(int u, int v, int c, int cost)
{
e.push_back(edge(u, v, c, , cost));
e.push_back(edge(v, u, , , -cost));
int m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
}
bool bellman(int s, int t, int& flow, long long & cost)
{
memset(d, 0xef, sizeof(d));
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ;//源点s的距离设为0,标记入队
p[s] = ; a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的) queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
inq[u] = ;//入队列标记删除
for (int i = ; 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] = ; }//Bellman 算法入队
}
}
}
if (d[t] < )return false;//找不到增广路
flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow
cost += (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] ^ ].f -= a[t];//反向边减去流量 (和增广路算法一样)
}
return true;
}
int MaxcostMaxflow(int s, int t, long long & cost)
{
cost = ;
int flow = ;
while (bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost
return flow;//返回最大流,cost引用可以直接返回最小费用
} struct node
{
int l, r;
}exa[maxn];
bool cmp(node a,node b)
{
return a.l < b.l;
}
int main()
{
int n, m;
cin >> n >> m;
int s1 = ;
s = , t = * n + ;
for(int i=;i<=n;i++)
{
cin >> exa[i].l >> exa[i].r;
if (exa[i].l > exa[i].r) swap(exa[i].l, exa[i].r);
}
sort(exa + , exa + + n, cmp);
add(s, s1, m, );
for(int i=;i<=n;i++)
{
add(s1, + * i - , , );
add( + * i - , + * i,, exa[i].r - exa[i].l);
add( + * i, t, , );
for(int j=;j<i;j++)
{
if (exa[j].r <= exa[i].l) add( + * j, + * i - , , );
}
}
ll cost = ;
int ans = MaxcostMaxflow(s, t, cost);
printf("%lld\n", cost);
return ;
}

网络流 P3358 最长k可重区间集问题的更多相关文章

  1. (luogu P3358)最长k可重区间集问题 [TPLY]

    最长k可重区间集问题 题目链接 https://www.luogu.org/problemnew/show/3358 做法 所有点向下一个点连容量为k费用为0的边 l和r连容量为1费用为区间长度的边 ...

  2. 洛谷P3358 最长k可重区间集问题(费用流)

    题目描述 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度. 输入输出格式 输入格式: 的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重 ...

  3. 洛谷P3358 最长k可重区间集问题(费用流)

    传送门 因为一个zz错误调了一个早上……汇点写错了……spfa也写错了……好吧好像是两个…… 把数轴上的每一个点向它右边的点连一条边,容量为$k$,费用为$0$,然后把每一个区间的左端点向右端点连边, ...

  4. luogu P3358 最长k可重区间集问题

    网络流建图好难,这题居然是网络流(雾,一般分析来说,有限制的情况最大流情况可以拆点通过capacity来限制,比如只使用一次,把一个点拆成入点出点,capacity为1即可,这题是限制最大k重复,可以 ...

  5. P3358 最长k可重区间集问题

    题目链接 \(Click\) \(Here\) 这题的写法非常巧妙. 每个位置的点向它的下一个位置连一个容量为\(INF\)的边,从区间的左端点往右端点拉一条容量为\(1\),费用为区间长度的边,从起 ...

  6. 【Luogu】P3358最长k可重区间集问题(费用流)

    题目链接 这题费用瘤,数据貌似还是错的. 把线段抽象抽象拆成两个点,入点表示左端,出点表示右端,连上容量为1费用-长度的边. 不相交线段随便连下,源点向拆出的原点S'连费用为0容量k,然后跑费用流. ...

  7. 洛谷 P3358 最长k可重区间集问题 【最大费用最大流】

    同 poj 3680 https:www.cnblogs.com/lokiii/p/8413139.html #include<iostream> #include<cstdio&g ...

  8. 「网络流24题」「LuoguP3358」 最长k可重区间集问题(费用流

    题目描述 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度. 输入输出格式 输入格式: 的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重 ...

  9. 最长k可重区间集

      P3358 最长k可重区间集问题 P3357 最长k可重线段集问题 P3356 火星探险问题 P4012 深海机器人问题 P3355 骑士共存问题 P2754 [CTSC1999]家园 题目描述 ...

随机推荐

  1. poi的合并单元格和冻结行列

    //创建工作薄(excel) Workbook wb = new HSSFWorkbook(); //创建sheet Sheet createSheet = wb.createSheet(" ...

  2. Linux时间子系统之(十三):Tick Device layer综述

    专题文档汇总目录 Notes:从概念层次描述了tick-comm.oneshot tick.broadcast tick:重点介绍了tick和tickless概念及其区别,两种tick device: ...

  3. Securing Spring Cloud Microservices With OAuth2

    From Zero to OAuth2 in Spring cloud Today I am presenting hours of research about a (apparently) sim ...

  4. SwaggerUI--SosoApi

    1.SwaggerUI是什么? Swagger UI是一款RESTFUL接口的文档在线自动生成+功能测试功能软件. Swagger-UI 的官方地址:http://swagger.io/ Github ...

  5. MongoDB的安装启动及做成windows服务

    直接上干货. 官网地址:https://www.mongodb.com/download-center?jmp=nav#community 点击图中链接进入所有版本的下载列表 我下载的是3.6.5版本 ...

  6. MassTransit 实现发布/订阅

    MassTransit 介绍  先看下masstransit 官网介绍:MassTransit 是一个自由.开源.轻量级的消息总线, 用于使用. NET 框架创建分布式应用程序.MassTransit ...

  7. python中__del__使用方法

    创建对象后,python解释器默认调用__init__()方法.当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法.在python中,对于开发者来说很少会直接销 ...

  8. 如何解决python升级后yum报错

    当我们yum命令的时候,会提示 "File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxEr ...

  9. Python三元运算

    result = 值1 if 条件 else 值2 如果条件为真,result = 值1 如果条件为假, result = 值2.

  10. Java8-6-Predicate接口详解

    转自https://segmentfault.com/a/1190000012256677 Predicate函数式接口的主要作用就是提供一个test方法,接受一个参数返回一个布尔类型,Predica ...