洛谷P3357 最长k可重线段集问题(费用流)

题目描述http://www.cnblogs.com/zwfymqz/p/8559566.html

给定平面 x-O-yx−O−y 上 nn 个开线段组成的集合 II ,和一个正整数 kk 。试设计一个算法,从开线段集合 II 中选取出开线段集合 S\subseteq IS⊆I ,使得在 xx 轴上的任何一点 pp ,SS 中与直线 x=px=p 相交的开线段个数不超过 kk ,且\sum\limits_{z\in S}|z|z∈S∑​∣z∣ 达到最大。这样的集合 SS 称为开线段集合 II 的最长 kk 可重线段集。\sum\limits_{z\in S}|z|z∈S∑​∣z∣ 称为最长 kk 可重线段集的长度。

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

对于给定的开线段集合 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

说明

1\leq n\leq5001≤n≤500

1 \leq k \leq 131≤k≤13

这题与最长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\n",-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;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏李蔚蓬的专栏

第12周Python学习周记

>>> b = a                                #没有创建新的对象

12820
来自专栏小樱的经验随笔

洛谷 P1019 单词接龙【经典DFS,温习搜索】

P1019 单词接龙 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”...

39160
来自专栏赵俊的Java专栏

奇偶分割数组

17940
来自专栏图像识别与深度学习

2018-07-02Python数组

12730
来自专栏HansBug's Lab

1212: [HNOI2004]L语言

1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 643  Solved...

30250
来自专栏Python小屋

Python版堆排序算法

其他排序算法的Python实现请参考:Python版归并排序算法(附Python程序__name__属性用法演示视频),侏儒排序算法原理与Python实现,Py...

35650
来自专栏Petrichor的专栏

numpy: np.where

Note : 不接受 list 型的参数,只接受 `ndarray 型输入。

13830
来自专栏我的博客

C编程笔记

1.编译命令gcc test.c -o test 带上参数o就是指定编译文件名 2.printf(“%.2lf”,b) 其中前面2是小数点后位数,l是字母...

37450
来自专栏武培轩的专栏

排序算法-希尔排序

上一篇讲解了简单插入排序算法,以及在其基础上优化的二分插入排序算法,但是每次插入需要按间隔为 1 移动有序区的元素,效率不高,下面我们来介绍一种新的插入排序算法...

35640
来自专栏计算机视觉与深度学习基础

Leetcode 31 Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically...

20950

扫码关注云+社区

领取腾讯云代金券