网络流24题22最长k可重线段集问题

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流24题22最长k可重线段集问题相关的知识,希望对你有一定的参考价值。

题面戳我

sol

千万!千万!不要理解错题意了!最长K可重,不是说线段最多K可重!你以为计算几何?
原文:使得在\\(x\\)轴上的任何一点\\(p\\)\\(S\\)中与直线\\(x=p\\)相交的开线段个数不超过\\(k\\)
所以这题就和最长K可重区间集问题是一样的!
只是这里有个坑。线段可以垂直\\(x\\)轴对吧(废话),那么你直接离散化然后连边就会连出一个负边权的自!环!,然后spfa呵呵呵。死掉了。
为了解决这一问题,我们把所有横坐标都扩大两倍,然后左端点++。对于那些左右端点相等的线段,就把左端点++改为左端点--即可。这样既可以保证连接不形成环,且和原本的意义相同。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N = 1005;
const int inf = 1e9;
struct edge{int to,next,w,cost;}a[N<<2];
int n,k,l[N],r[N],x[N],y[N],val[N],o[N],len,s,t,head[N],cnt=1,dis[N],vis[N],pe[N];
long long ans;
queue<int>Q;
long long sqr(int x){return 1ll*x*x;}
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<\'0\'||ch>\'9\')&&ch!=\'-\') ch=getchar();
	if (ch==\'-\') w=0,ch=getchar();
	while (ch>=\'0\'&&ch<=\'9\') x=(x<<3)+(x<<1)+ch-\'0\',ch=getchar();
	return w?x:-x;
}
void link(int u,int v,int w,int cost)
{
	a[++cnt]=(edge){v,head[u],w,cost};
	head[u]=cnt;
	a[++cnt]=(edge){u,head[v],0,-cost};
	head[v]=cnt;
}
bool spfa()
{
	memset(dis,63,sizeof(dis));
	dis[s]=0;Q.push(s);
	while (!Q.empty())
	{
		int u=Q.front();Q.pop();
		for (int e=head[u];e;e=a[e].next)
		{
			int v=a[e].to;
			if (a[e].w&&dis[v]>dis[u]+a[e].cost)
			{
				dis[v]=dis[u]+a[e].cost;pe[v]=e;
				if (!vis[v]) vis[v]=1,Q.push(v);
			}
		}
		vis[u]=0;
	}
	if (dis[t]==dis[0]) return false;
	int sum=inf;
	for (int i=t;i!=s;i=a[pe[i]^1].to)
		sum=min(sum,a[pe[i]].w);
	ans-=1ll*sum*dis[t];
	for (int i=t;i!=s;i=a[pe[i]^1].to)
		a[pe[i]].w-=sum,a[pe[i]^1].w+=sum;
	return true;
}
int main()
{
	n=gi();k=gi();
	for (int i=1;i<=n;i++)
	{
		l[i]=gi(),x[i]=gi(),r[i]=gi(),y[i]=gi();
		val[i]=sqrt(sqr(r[i]-l[i])+sqr(y[i]-x[i]));
		l[i]*=2;r[i]*=2;
		if (l[i]==r[i]) l[i]--;
		else l[i]++;
		o[++len]=l[i];o[++len]=r[i];
	}
	sort(o+1,o+len+1);
	len=unique(o+1,o+len+1)-o-1;
	s=len+1;t=len+2;
	link(s,1,k,0);link(len,t,k,0);
	for (int i=1;i<len;i++)
		link(i,i+1,k,0);
	for (int i=1;i<=n;i++)
	{
		l[i]=lower_bound(o+1,o+len+1,l[i])-o;
		r[i]=lower_bound(o+1,o+len+1,r[i])-o;
		link(l[i],r[i],1,-val[i]);
	}
	while (spfa()) ;
	printf("%lld\\n",ans);
	return 0;
}

以上是关于网络流24题22最长k可重线段集问题的主要内容,如果未能解决你的问题,请参考以下文章

最长k可重区间集问题网络流24题

网络流24题之最长k可重线段集问题

网络流24题(好大的坑啊)

网络流24题21最长k可重区间集问题

「网络流24题」「LuoguP3358」 最长k可重区间集问题

[网络流 24 题]最长k可重区间集(费用流)