• 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题


    题目描述

    给定平面 ( ext{xoy})(n) 个开线段组成的集合 ( ext{I}) ,和一个正整数 (k) ,试设计一个算法。

    从开线段集合 ( ext{I}) 中选取出开线段集合 ( ext{S}in ext{I}) ,

    使得在x轴上的任何一点 ( ext{p})( ext{S}) 中与直线 ( ext{x}= ext{p}) 相交的开线段个数不超过 ( ext{k})

    (sum_{ ext{z} in ext{S}}|z|) 达到最大。

    这样的集合 ( ext{S}) 称为开线段集合 ( ext{I}) 的最长 ( ext{k}) 可重线段集的长度。

    对于任何开线段 ( ext{z}) ,设其断电坐标为 (( x_0 , y_0 ))(( x_1 , y_1 ))

    则开线段 ( ext{z}) 的长度 (| ext{z}|) 定义为:(|z| = lfloor sqrt{ ( x_1 - x_0 ) ^ 2 + ( y_1 - y_0 )^2 } floor)

    对于给定的开线段集合 ( ext{I}) 和正整数 ( ext{k}) ,计算开线段集合 ( ext{I}) 的最长 ( ext{k}) 可重线段集的长度。

    输入格式

    文件的第一 行有二个正整数 ( ext{n})( ext{k}) ,分别表示开线段的个数和开线段的可重迭数。接下来的 ( ext{n}) 行,每行有4个整数,表示开线段的2个端点坐标。

    输出格式

    程序运行结束时,输出计算出的最长k可重线段集的长度。

    样例

    样例输入

    4 2
    1 2 7 3
    6 5 8 3
    7 8 10 5
    9 6 13 9
    

    样例输出

    17
    

    数据范围与提示

    (1leq nleq500)

    (1 leq k leq 13)

    题解

    这道题与【刷题】LOJ 6014 「网络流 24 题」最长 k 可重区间集有很大的相似度

    这里基于明白那道题的做法之上给出这道题的做法

    把线段对应到 (x) 轴上,其实就变成了一些区间了,和那道题一样

    但是有一种特殊情况,就是存在线段 (x=r) 的时候,如果按照那题的方式建图,就会出现自环,所以要换一种建图方式

    考虑把每个区间的左右端点都变成 (2) 倍(离散化后),如果 (l=r) ,那么 (r) 加一,否则 (l) 加一,这样就可以防止自环的出现(想一想为什么)

    然后同样的方式跑答案就好了

    #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=2000+10,MAXM=(MAXN<<1),inf=0x3f3f3f3f;
    int n,k,r,e=1,s,t,beg[MAXN],cur[MAXN],L[MAXN],R[MAXN],vis[MAXN],level[MAXN],p[MAXN],nex[MAXM<<1],to[MAXM<<1],cap[MAXM<<1],was[MAXM<<1],clk;
    ll answas,val[MAXN];
    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;
    			answas+=1ll*f*was[i];
    			maxflow-=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)
    	{
    		int x1,y1,x2,y2;read(x1);read(y1);read(x2);read(y2);
    		val[i]=std::sqrt(1ll*(x1-x2)*(x1-x2)+1ll*(y1-y2)*(y1-y2));
    		L[i]=(x1<<1),R[i]=(x2<<1);
    		if(L[i]>R[i])std::swap(L[i],R[i]);
    		if(L[i]==R[i])R[i]++;
    		else 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;
    }
    
  • 相关阅读:
    时间选择器UIDatePicker的使用
    在app中屏蔽第三方键盘
    plist文件的相关操作
    查看mac上的隐藏文件
    设置ARC有效或者无效
    Linux 下源代码安装编译 ImageMagick6.8.48 且使其支持 JPEG
    Linux Netcat 命令—网络工具中的瑞士军刀
    Linux 好书、经典书籍推荐
    让你拥有超能力:程序员应该掌握的统计学公式
    shell 脚本实现的守护进程
  • 原文地址:https://www.cnblogs.com/hongyj/p/9443388.html
Copyright © 2020-2023  润新知