$\mathtt{Updata\ 2019.11.13}$ 今天膜你赛做到了原题,不得不来修一下 $blog$

题面

有 $n$ 条平行于坐标轴线段,取的线段要求不相交,最大化所取线段数目

解题思路

二分图匹配

分析

把平行于 $x$ 轴和平行于 $y$ 轴的线段分别看成两个集合,这样就和二分图有关了

从最小割的方面想,要想所选的数目尽量多,那么就是不能选的尽量少

显然,如果两条线段有相交的部分,则有一条必不能取,因此以是否相交为依据建边,再跑一个最小割,或者说就是二分图的最大匹配,答案即为 $n-Maxflow$

可以用 $Dinic$ 或者匈牙利算法实现

warning

个人认为最大的坑点是所给的线段的端点不是有序的,比如平行于 $x$ 轴的线段的两个端点可能并不是按照两点 $x$ 坐标的大小给出,要特别判断,否则,判断相交的时候就 $GG$ 了,当然不要忘记网络流建边开四十倍

Code

#include<bits/stdc++.h>
#define rgt register
#define rint rgt int
#define LL long long
#define rll rgt LL
#define inf 0x7f7f7f7f
#define M 3000003
#define N 257
using namespace std;
template<class K>inline bool cmax(K&a,const K&b){return(a<b)?a=b,1:0;}
template<class K>inline bool cmin(K&a,const K&b){return(a>b)?a=b,1:0;}
inline int read() {
    rint s=0;
    rgt char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) s=(s<<1)+(s<<3)+c-'0',c=getchar();
    return s;
}
struct Edge{
    int to,nxt,cap;
    Edge(int a,int b,int c):to(a),nxt(b),cap(c){}
    Edge(){}
}b[M];
struct segment{
    int lx,ly,rx,ry;
    inline void in() {
        lx=read(),ly=read(),
        rx=read(),ry=read();
        if(lx>rx) lx^=rx^=lx^=rx;//可能不是有序的
        if(ly>ry) ly^=ry^=ly^=ry;
    }
}A[N],B[N],c;
int n,la,lb,t=1,S,T,head[N],dep[N],Maxflow;
inline void add(rint x,rint y) {
    b[++t]=Edge(y,head[x],1),head[x]=t,
    b[++t]=Edge(x,head[y],0),head[y]=t;
}
inline bool cross(rgt segment a,rgt segment b) {//判断相交
    return b.lx<=a.lx&&a.lx<=b.rx&&a.ly<=b.ly&&b.ly<=a.ry;
}
inline bool BFS() {
    rint i,to,cur,cap;
    queue<int>p;
    memset(dep,0,sizeof(dep));
    dep[S]=1,p.push(S);
    while(!p.empty()) {
        cur=p.front(),p.pop();
        for(i=head[cur];i;i=b[i].nxt) {
            to=b[i].to;
            if(b[i].cap&&!dep[to]) {
                dep[to]=dep[cur]+1;
                if(to==T) return 1;
                p.push(to);
            }
        }
    }return 0;
}
inline int Dinic(rint k,rint flow) {
    if(k==T) return flow;
    rint i,to,cap,res,rest=flow;
    for(i=head[k];i&&rest;i=b[i].nxt) {
        to=b[i].to,cap=b[i].cap;
        if(cap&&dep[to]==dep[k]+1) {
            res=Dinic(to,min(rest,cap));
            if(!res) dep[to]=0;
            b[i].cap-=res,
            b[i^1].cap+=res,
            rest-=res;
        }
    }
    return flow-rest;
}
int main() {
    rint i,j,flow;n=read();
    for(i=1;i<=n;i++) {
        c.in();
        if(c.lx==c.rx) A[++la]=c;//按照平行的坐标分组
        else B[++lb]=c;
    }T=n+1;
    for(i=1;i<=la;i++) add(S,i);//超源和超汇
    for(i=1;i<=lb;i++) add(i+la,T);
    for(i=1;i<=la;i++)
        for(j=1;j<=lb;j++)
            if(cross(A[i],B[j]))//相交就建边
                add(i,j+la);
    while(BFS())//Dinic大法吼
        while((flow=Dinic(S,inf)))
            Maxflow+=flow;
    printf("%d",n-Maxflow);
    return 0;
}

devil.