zoukankan      html  css  js  c++  java
  • 【刷题】LOJ 6014 「网络流 24 题」最长 k 可重区间集

    题目描述

    给定实直线 (L)(n) 个开区间组成的集合 (I) ,和一个正整数 (k) ,试设计一个算法,从开区间集合 (I) 中选取出开区间集合 (S subseteq I) ,使得在实直线 (L) 的任何一点 (x)(S) 中包含点 (x) 的开区间个数不超过 (k) 。且 (sumlimits_{z in S} | z |) 达到最大。这样的集合 (S) 称为开区间集合 (I) 的最长 (k) 可重区间集。(sumlimits_{z in S} | z |) 称为最长 (k) 可重区间集的长度。

    对于给定的开区间集合 (I) 和正整数 (k) ,计算开区间集合 (I) 的最长 (k) 可重区间集的长度。

    输入格式

    文件的第 (1) 行有 (2) 个正整数 (n)(k) ,分别表示开区间的个数和开区间的可重迭数。

    接下来的 (n) 行,每行有 (2) 个整数 (l_i)(r_i) ,表示开区间的左右端点坐标,注意可能有 (l_i > r_i) ,此时请将其交换

    输出格式

    输出最长 (k) 可重区间集的长度。

    样例

    样例输入

    4 2
    1 7
    6 8
    7 10
    9 13
    

    样例输出

    15
    

    数据范围与提示

    (1 leq n leq 500, 1 leq k leq 3)

    题解

    先离散化

    然后每个点向后面一个点连容量为 (inf) ,费用为 (0) 的边

    对于一个区间 (l,r) ,从 (l) 连向 (r) ,容量为 (1) ,费用为其长度的相反数,代表一个区间只能选一次,选一次的贡献为它的长度

    这样建模跑费用流就可以使答案最大

    但是还有每个点只能被覆盖 (k) 的限制

    那么源点向 (1) 号点连容量为 (k) ,费用为 (0) 的边

    (n) 号点向汇点连容量为 (k) ,费用为 (0) 的边

    在一次增广中,每个点都只会被经过一次

    那么最大流一定为 (k) ,即 (k) 次增广,所以每个点只会被经过 (k) 次,满足题目限制

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=1000+10,MAXM=(MAXN<<1),inf=0x3f3f3f3f;
    int n,k,e=1,beg[MAXN],cur[MAXN],L[MAXN],R[MAXN],r,level[MAXN],p[MAXN],vis[MAXN],clk,s,t,nex[MAXM<<1],to[MAXM<<1],cap[MAXM<<1],was[MAXM<<1],val[MAXN];
    ll answas;
    std::queue<int> q;
    std::vector<int> V;
    std::map<int,int> M;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y,int z,int w)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    	cap[e]=z;
    	was[e]=w;
    	to[++e]=x;
    	nex[e]=beg[y];
    	beg[y]=e;
    	cap[e]=0;
    	was[e]=-w;
    }
    inline void discretization()
    {
    	for(register int i=1;i<=n;++i)V.push_back(L[i]),V.push_back(R[i]);
    	std::sort(V.begin(),V.end());
    	V.erase(std::unique(V.begin(),V.end()),V.end());
    	for(register int i=0,lt=V.size();i<lt;++i)M[V[i]]=i+1;
    	for(register int i=1;i<=n;++i)L[i]=M[L[i]],R[i]=M[R[i]],chkmax(r,R[i]);
    }
    inline bool bfs()
    {
    	memset(level,inf,sizeof(level));
    	level[s]=0;
    	p[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		p[x]=0;
    		for(register int i=beg[x];i;i=nex[i])
    			if(cap[i]&&level[to[i]]>level[x]+was[i])
    			{
    				level[to[i]]=level[x]+was[i];
    				if(!p[to[i]])p[to[i]]=1,q.push(to[i]);
    			}
    	}
    	return level[t]!=inf;
    }
    inline int dfs(int x,int maxflow)
    {
    	if(x==t||!maxflow)return maxflow;
    	vis[x]=clk;
    	int res=0;
    	for(register int &i=cur[x];i;i=nex[i])
    		if((vis[to[i]]^vis[x])&&cap[i]&&level[to[i]]==level[x]+was[i])
    		{
    			int f=dfs(to[i],min(maxflow,cap[i]));
    			res+=f;
    			cap[i]-=f;
    			cap[i^1]+=f;
    			maxflow-=f;
    			answas+=1ll*was[i]*f;
    			if(!maxflow)break;
    		}
    	vis[x]=0;
    	return res;
    }
    inline void MCMF()
    {
    	while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),dfs(s,inf);
    }
    int main()
    {
    	read(n);read(k);
    	for(register int i=1;i<=n;++i)
    	{
    		read(L[i]);read(R[i]);
    		if(L[i]>R[i])std::swap(L[i],R[i]);
    		val[i]=R[i]-L[i];
    	}
    	discretization();
    	s=r+1,t=s+1;
    	insert(s,1,k,0);insert(r,t,k,0);
    	for(register int i=1;i<r;++i)insert(i,i+1,inf,0);
    	for(register int i=1;i<=n;++i)insert(L[i],R[i],1,-val[i]);
    	MCMF();
    	write(-answas,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    查看Java中每个数据类型所占的位数,和表示数值的范围,并得出结论。
    同名变量的屏蔽原则
    反码,补码,原码
    机器学习概念性知识总结
    图的最短路径问题
    System Design 笔记及代码(系统设计)
    2016网易游戏实习算法题解(今年找暑期实习的时候参加的)
    Google java style
    18.1---不用加号的加法(CC150)
    Java模板模式(template)
  • 原文地址:https://www.cnblogs.com/hongyj/p/9433635.html
Copyright © 2011-2022 走看看