zoukankan      html  css  js  c++  java
  • 洛谷P3357 最长k可重线段集问题(费用流)

    题目描述

    给定平面 x-O-yxOy 上 nn 个开线段组成的集合 II ,和一个正整数 kk 。试设计一个算法,从开线段集合 II 中选取出开线段集合 Ssubseteq ISI ,使得在 xx 轴上的任何一点 pp ,SS 中与直线 x=px=p 相交的开线段个数不超过 kk ,且sumlimits_{zin S}|z|zSz∣ 达到最大。这样的集合 SS 称为开线段集合 II 的最长 kk 可重线段集。sumlimits_{zin S}|z|zSz∣ 称为最长 kk 可重线段集的长度。

    对于任何开线段 zz ,设其断点坐标为 (x_0,y_0)(x0,y0) 和 (x_1,y_1)(x1,y1) ,则开线段 zz 的长度 |z|z∣ 定义为:|z|=lfloorsqrt{(x_1-x_0)^2+(y_1-y_0)^2} floorz=(

    对于给定的开线段集合 II 和正整数 kk ,计算开线段集合 II 的最长 kk 可重线段集的长度。

    输入输出格式

    输入格式:

    文件的第一 行有 22 个正整数 nn 和 kk ,分别表示开线段的个数和开线段的可重叠数。

    接下来的 nn 行,每行有 44 个整数,表示开线段的 22 个端点坐标。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    4 2
    1 2 7 3
    6 5 8 3
    7 8 10 5
    9 6 13 9 
    输出样例#1: 复制
    17

    说明

    1leq nleq5001n500

    1 leq k leq 131k13

     

    这题与最长k可重区间集问题本质上是一样的,

    但是有一种特殊情况,当这条直线垂直于$y$轴时,我们在连边的过程中会产生负环

    怎么办呢?

    这里有一个神仙操作

    把两个点的$x$值全部*2,若相同,则较小的-1,否则较小的+1

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #define int long long 
    #define AddEdge(x,y,z,f) add_edge(x,y,z,f),add_edge(y,x,-z,0)
    using namespace std;
    const int MAXN=1e5+10;
    const int INF=1e8+10;
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int N,K,S,T;
    int anscost=0;
    struct node
    {
        int u,v,w,f,nxt;
    }edge[MAXN];
    int head[MAXN],num=2;
    inline void add_edge(int x,int y,int z,int f)
    {
        edge[num].u=x;
        edge[num].v=y;
        edge[num].w=z;
        edge[num].f=f;
        edge[num].nxt=head[x];
        head[x]=num++;
    }
    int Pre[MAXN],vis[MAXN],dis[MAXN];
    bool SPFA()
    {
        queue<int>q;
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[S]=0;
        q.push(S);
        while(q.size()!=0)
        {
            int p=q.front();q.pop();
            vis[p]=0;
            for(int i=head[p];i!=-1;i=edge[i].nxt)
            {
                if(dis[edge[i].v]>dis[p]+edge[i].w&&edge[i].f)
                {
                    dis[edge[i].v]=dis[p]+edge[i].w;
                    Pre[edge[i].v]=i;
                    if(!vis[edge[i].v])
                        vis[edge[i].v]=1,q.push(edge[i].v);
                }
            }
        }
        return dis[T]<=INF;
    }
    void f()
    {
        int nowflow=INF;
        for(int now=T;now!=S;now=edge[Pre[now]].u)
            nowflow=min(nowflow,edge[Pre[now]].f);
        for(int now=T;now!=S;now=edge[Pre[now]].u)
            edge[Pre[now]].f-=nowflow,
            edge[Pre[now]^1].f+=nowflow;
        anscost+=nowflow*dis[T];
    }
    void MCMF()
    {
        int ans=0;
        while(SPFA())
            f();
        printf("%lld
    ",-anscost);
    }
    int L[MAXN],R[MAXN],date[MAXN],tot=0;
    struct Point
    {
        int xx1,yy1,xx2,yy2,L;
    }P[MAXN];
    double GetL(int n)
    {
        return floor((double)sqrt((P[n].xx1-P[n].xx2)*(P[n].xx1-P[n].xx2) + (P[n].yy1-P[n].yy2)*(P[n].yy1-P[n].yy2)));
    }
    main()
    {
        #ifdef WIN32
        freopen("a.in","r",stdin);
        #else
        #endif
        memset(head,-1,sizeof(head));
        N=read();K=read();
        for(int i=1;i<=N;i++)
        {
            P[i].xx1=read(),P[i].yy1=read(),P[i].xx2=read(),P[i].yy2=read();
            if(P[i].xx1>P[i].xx2) 
                swap(P[i].xx1,P[i].xx2),
                swap(P[i].yy1,P[i].yy2);
            P[i].L=GetL(i);
            P[i].xx1*=2;
            P[i].xx2*=2;
            if(P[i].xx1==P[i].xx2) P[i].xx1--;
            else P[i].xx1++;
            date[++tot]=P[i].xx1,date[++tot]=P[i].xx2;
        }
    
        sort(date+1,date+tot+1);
        int num=unique(date+1,date+tot+1)-date-1;
        for(int i=1;i<=num-1;i++)
            AddEdge(i,i+1,0,INF);
        for(int i=1;i<=N;i++)
        {
            P[i].xx1=lower_bound(date+1,date+num+1,P[i].xx1)-date;
            
            P[i].xx2=lower_bound(date+1,date+num+1,P[i].xx2)-date;
            
            AddEdge(P[i].xx1,P[i].xx2,-P[i].L,1);
        }
        S=0,T=num*2;
        AddEdge(S,1,0,K);
        AddEdge(num,T,0,K);
        MCMF();
        return 0;
    }
  • 相关阅读:
    NOJ 1116 哈罗哈的大披萨 【淡蓝】 状态压缩DP
    优先队列原理与实现【转】
    testC-I
    济南NOIP冬令营 选拔(select)
    P4747 D’s problem(d)
    P4746 C’s problem(c)
    P4745 B’s problem(b)
    P4744 A’s problem(a)
    [bzoj] 1004: [HNOI2008]Cards
    NOIP2013 表达式求值
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8560790.html
Copyright © 2011-2022 走看看