zoukankan      html  css  js  c++  java
  • 【网络流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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    awt
    登录校验 简单实现
    事务隔离级别
    事务的四大特性(ACID)
    多线程简单了解
    Eureka bug
    什么是存储过程
    filter和servlet的区别
    说说你对多线程锁机制的理解
    session的生命周期,session何时创建,何时销毁,session销毁的方式
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8194230.html
Copyright © 2011-2022 走看看