ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【洛谷3358】最长k可重区间集问题(费用流)

2021-02-24 19:34:35  阅读:195  来源: 互联网

标签:PS 可重 洛谷 int dc 选择 区间 3358 define


点此看题面

  • 给定\(n\)个开区间和一个正整数\(k\)。
  • 要求从中选出若干个区间,满足同一个点不会被选择超过\(k\)次,并最大化选出的区间长度之和。
  • \(n\le500,k\le3\)

一种很好的建图思路

说实话,这种题型是我长久以来一直很想知道怎么做的,果然网络流二十四题真的是经典好题。

我们可以把原题面改成选择\(k\)次,每次可以选择任意个不相交的区间。

为了实现选\(k\)次,我们需要从超级源向第一个点连一条容量为\(k\)、价值为\(0\)的边。

然后,我们从坐标轴上每个点向相邻的下一个点(最后一个点向超级汇)连一条容量为\(k\)、价值为\(0\)的边,表示一次选择的两个区间之间可以不连续。

对于选一个区间的情况,我们从这个区间的左端点向右端点连一条容量为\(1\)、价值为区间长度的边,因为选择这个区间就不能再选与它有交的其他区间。

然后跑一遍费用流就结束了。

代码:\(O(Dinic)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500
#define INF (int)1e9
using namespace std;
int n,k,a[N+5],b[N+5],dc,dv[N+5];
class MinCostMaxFlow
{
	private:
		#define PS (N+2)
		#define ES (2*N+2)
		#define s (dc+1)
		#define t dc
		#define E(x) ((((x)-1)^1)+1)
		int ee,lnk[PS+5];struct edge {int to,nxt,F,C;}e[2*ES+5];
		int lst[PS+5],IQ[PS+5],F[PS+5],C[PS+5];queue<int> q;
		I bool SPFA()//SPFA求增广路
		{
			RI i,k;for(i=1;i<=s;++i) F[i]=INF,C[i]=-1e18;q.push(s),C[s]=0;
			W(!q.empty()) for(i=lnk[k=q.front()],q.pop(),IQ[k]=0;i;i=e[i].nxt)
			{
				if(!e[i].F||C[k]+e[i].C<=C[e[i].to]) continue;
				C[e[i].to]=C[k]+e[lst[e[i].to]=i].C,F[e[i].to]=min(F[k],e[i].F),
				!IQ[e[i].to]&&(q.push(e[i].to),IQ[e[i].to]=1);
			}return F[t]^INF;
		}
	public:
		I void Add(CI x,CI y,CI f,CI c)//建边
		{
			e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f,e[ee].C=c,
			e[++ee].nxt=lnk[y],e[lnk[y]=ee].to=x,e[ee].F=0,e[ee].C=-c;
		}
		I int MCMF()//最大费用最大流
		{
			RI x,g=0;W(SPFA()) {g+=C[t]*F[t],x=t;
				W(x^s) e[lst[x]].F-=F[t],e[E(lst[x])].F+=F[t],x=e[E(lst[x])].to;}
			return g;
		}
}D;
int main()
{
	RI i;for(scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d%d",a+i,b+i),dv[i]=a[i];
	#define G(x) (lower_bound(dv+1,dv+dc+1,x)-dv)
	dv[n+1]=2e9,sort(dv+1,dv+n+2),dc=unique(dv+1,dv+n+2)-dv-1;//离散化
	for(D.Add(s,1,k,0),i=1;i^dc;++i) D.Add(i,i+1,k,0);//超级源向第一个点,每个点向后一个点(dc为超级汇)
	for(i=1;i<=n;++i) D.Add(G(a[i]),G(b[i]),1,b[i]-a[i]);//每个左端点向右端点连边表示选择一个区间
	return printf("%d\n",D.MCMF()),0;
}

标签:PS,可重,洛谷,int,dc,选择,区间,3358,define
来源: https://www.cnblogs.com/chenxiaoran666/p/Luogu3358.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有