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. Centos7 升级 gcc

    特别蛋疼的开始 最痛苦的就是一步一个坑 为了安装 vue.js,听说要安装 node.js,听说为了安装 node.js碰上了gcc版本不够的问题,此时我特别特别特别的想念盖茨大大 下载 gcc gc ...

  2. String和StringBuffer的区别?

    这个我经常用的是String,说真的,用StringBuffer的次数还真是少,唯一让我觉得特别的方法就是appand这个方法是StringBuffer独有的,那么他们到底有什么区别呢,我们知道Str ...

  3. 闪回工具flashback

    Ⅰ.背景 早先操作数据误操作后,我们一般通过全量备份+binlog的方式来实现恢复(前滚) 有时只想撤销一个几分钟前的操作,采用这种方式就会显得很笨重 大家都知道Oracle有个叫做flashback ...

  4. 什么是设计思维Design Thinking——风靡全球的创造力培养方法

    “把学习带到现实中,让孩子用自己的力量创造改变,可以直接提升他们的幸福感和竞争力.” 这是“全球孩童创意行动”的发起人——Kiran Sethi在TED演讲时说的一句话,这个行动旨在引导中小学生主动寻 ...

  5. java中位运算

    1byte(字节)=8bit(比特) 1 0 0 0 0 0 0 0 1   2进制的1的原码 反码 补码 0 0 0 0 0 0 0 0   2进制的0的原码 反码 补码 -1 1 0 0 0 0 ...

  6. 用java8重写Arrays.sort(oldWay, new Comparator<String>(){@Override public int compare(String s1, String s2)});

    参考https://www.liaoxuefeng.com/article/001411306573093ce6ebcdd67624db98acedb2a905c8ea4000/ Java 8终于引进 ...

  7. string_array.go

    package app import (     "strings" ) type StringArray []string func (a *StringArray) Set(s ...

  8. Java多线程简介

    Java多线程简介 Java中内置了对多线程的支持,让多线程的开发方便很多,但同时也带来了另外的复杂,线程间的交互以及很多的不确定性让多线程又显得很复杂.在此只是针对Java中多线程的基础做些说明,有 ...

  9. 在使用MFC对话框时遇到的用户交互

    有时我们需要点击对话框上的一个按钮的时候,对话框隐藏起来,然后执行完某个操作后,对话框又弹出来, 这时我们可以使用BeginEditorCommand()和CompleteEditorCommand( ...

  10. 不吹不擂,你想要的Python面试都在这里了【315+道题】

    写在前面 近日恰逢老男孩全栈8期毕业季,课程后期大家“期待+苦逼”的时刻莫过于每天早上内容回顾和面试题问答部分[临近毕业每天课前用40-60分钟对之前内容回顾.提问和补充,专挑班里不爱说话就的同学回答 ...