网络流 P3358 最长k可重区间集问题
P3358 最长k可重区间集问题
题目描述
对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度。
输入输出格式
输入格式:
的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重迭数。接下来的 n行,每行有 2 个整数,表示开区间的左右端点坐标。
输出格式:
将计算出的最长 k可重区间集的长度输出
输入输出样例
说明
对于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可重区间集问题的更多相关文章
- (luogu P3358)最长k可重区间集问题 [TPLY]
最长k可重区间集问题 题目链接 https://www.luogu.org/problemnew/show/3358 做法 所有点向下一个点连容量为k费用为0的边 l和r连容量为1费用为区间长度的边 ...
- 洛谷P3358 最长k可重区间集问题(费用流)
题目描述 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度. 输入输出格式 输入格式: 的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重 ...
- 洛谷P3358 最长k可重区间集问题(费用流)
传送门 因为一个zz错误调了一个早上……汇点写错了……spfa也写错了……好吧好像是两个…… 把数轴上的每一个点向它右边的点连一条边,容量为$k$,费用为$0$,然后把每一个区间的左端点向右端点连边, ...
- luogu P3358 最长k可重区间集问题
网络流建图好难,这题居然是网络流(雾,一般分析来说,有限制的情况最大流情况可以拆点通过capacity来限制,比如只使用一次,把一个点拆成入点出点,capacity为1即可,这题是限制最大k重复,可以 ...
- P3358 最长k可重区间集问题
题目链接 \(Click\) \(Here\) 这题的写法非常巧妙. 每个位置的点向它的下一个位置连一个容量为\(INF\)的边,从区间的左端点往右端点拉一条容量为\(1\),费用为区间长度的边,从起 ...
- 【Luogu】P3358最长k可重区间集问题(费用流)
题目链接 这题费用瘤,数据貌似还是错的. 把线段抽象抽象拆成两个点,入点表示左端,出点表示右端,连上容量为1费用-长度的边. 不相交线段随便连下,源点向拆出的原点S'连费用为0容量k,然后跑费用流. ...
- 洛谷 P3358 最长k可重区间集问题 【最大费用最大流】
同 poj 3680 https:www.cnblogs.com/lokiii/p/8413139.html #include<iostream> #include<cstdio&g ...
- 「网络流24题」「LuoguP3358」 最长k可重区间集问题(费用流
题目描述 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度. 输入输出格式 输入格式: 的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重 ...
- 最长k可重区间集
P3358 最长k可重区间集问题 P3357 最长k可重线段集问题 P3356 火星探险问题 P4012 深海机器人问题 P3355 骑士共存问题 P2754 [CTSC1999]家园 题目描述 ...
随机推荐
- 并发容器之CopyOnWriteArraySet
CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法. 具体 ...
- SSM-SpringMVC-25:SpringMVC异常顶级之自定义异常解析器
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 上篇博客相信大家也看到了,自定义异常,用了SimpleMappingExceptionResolver这个解析 ...
- OAthe2 Login use OkHttpClient and OAuth2RestTemplate
http://samchu.logdown.com/posts/1437422-oathe2-login-use-okhttpclient-and-oauth2resttemplate?utm_sou ...
- 一次故障解决过程梳理:mysql varchar text timestamp
CHAR 类型的一个变体是 VARCHAR 类型,char(M),M是指字节长度,和varchar(M)一样 故障原因:mysql主键设置为int(9),但数据量已经大于int(9)的范围了 tips ...
- checkbox事件的变化
<input type="checkbox" checked={this.state.checked} onChange={this.checkedChangeHandler ...
- Hexo博客搭建
http://www.jianshu.com/p/e99ed60390a8 http://blog.csdn.net/xuezhisdc/article/details/53130328 注意点: 1 ...
- 两个标签页定位第二个标签页元素时显示element not visible
问题描述 web页面有两个标签页, 当转换到第二个标签页定位元素时, 显示element not visible. 代码 ... //省略 WebElement ele= browser.getEle ...
- Mave手动安装jar包
今天配置Maven项目时有一个相应的jdbc驱动jar包导不进去,就自己导入了. 首先在官网上下载该jar包,地址为http://mvnrepository.com/ 点击jar下载. 用maven命 ...
- B20J_2836_魔法树_树链剖分+线段树
B20J_2836_魔法树_树链剖分+线段树 题意: 果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u].初始时,这个果树的每个节点上都没有果子(即0个果子). Add u v d ...
- 解决linux netcore https请求使用自签名证书忽略安全检查方法
当前系统环境:centos7 x64. dotnet 2.0. 不管是 ServicePointManager.ServerCertificateValidationCallback = (a, b, ...