• [网络流24题] 最长k可重线段集问题 (费用流)


    洛谷传送门 LOJ传送门

    最长k可重区间集问题的加强版

    大体思路都一样的,不再赘述,但有一些细节需要注意

    首先,坐标有负数,而且需要开$longlong$算距离

    但下面才是重点:

    我们把问题放到了二维平面内,如果出现了垂直于$x$轴的线段,该如何处理呢?直接当成线段处理显然不可取

    假设这条线段的横坐标是$x$

    1.它不会对从$x$开始的倾斜线段产生任何影响,但会和穿过$x$的倾斜直线抢位置

    2.它会和同样在$x$垂直的线段抢位置

    我用了一个比较笨的做法,先把横坐标离散,再把离散后的横坐标抻成原来的$2$倍,垂直线段横坐标为$2x-1$,倾斜线段横坐标是$2x$,问题就被解决了

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define N1 2005
     6 #define M1 200010
     7 #define ll long long
     8 #define dd double
     9 #define inf 0x3f3f3f3f
    10 #define maxn 100000
    11 using namespace std;
    12 
    13 int gint()
    14 {
    15     int ret=0,fh=1;char c=getchar();
    16     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    17     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    18     return ret*fh;
    19 }
    20 int n,K,S,T;
    21 struct Edge{
    22 int head[N1],to[M1<<1],nxt[M1<<1],flow[M1<<1],dis[M1<<1],cte;
    23 void ae(int u,int v,int F,int D)
    24 {
    25     cte++; to[cte]=v; flow[cte]=F; dis[cte]=D;
    26     nxt[cte]=head[u]; head[u]=cte;
    27 }
    28 }e;
    29 
    30 int que[M1<<1],hd,tl,dis[N1],id[N1],flow[N1],use[N1];
    31 int spfa()
    32 {
    33     int x,j,v;
    34     memset(dis,-1,sizeof(dis)); memset(flow,0,sizeof(flow)); memset(use,0,sizeof(use));
    35     hd=1,tl=0; que[++tl]=S; dis[S]=0; use[S]=1; flow[S]=inf;
    36     while(hd<=tl)
    37     {
    38         x=que[hd++]; 
    39         for(j=e.head[x];j;j=e.nxt[j])
    40         {
    41             v=e.to[j]; 
    42             if( e.flow[j]>0 && dis[v]<dis[x]+e.dis[j] )
    43             {
    44                 dis[v]=dis[x]+e.dis[j]; id[v]=j; 
    45                 flow[v]=min(flow[x],e.flow[j]);
    46                 if(!use[v]) que[++tl]=v, use[v]=1;
    47             }
    48         }
    49         use[x]=0;
    50     }
    51     return dis[T]!=-1;
    52 }
    53 int EK()
    54 {
    55     int tcost=0,mxflow=0,x;
    56     while(spfa())
    57     {
    58         mxflow+=flow[T]; tcost+=flow[T]*dis[T];
    59         for(x=T;x!=S;x=e.to[id[x]^1])
    60         {
    61             e.flow[id[x]]-=flow[T]; 
    62             e.flow[id[x]^1]+=flow[T]; 
    63         }
    64     }
    65     return tcost;
    66 }
    67 
    68 int l[N1],r[N1],p[N1],len[N1],t[N1<<1],cnt;
    69 int main()
    70 {
    71     scanf("%d%d",&n,&K); 
    72     int i,j,x,y,ma; e.cte=1;
    73     for(i=1;i<=n;i++)
    74     {
    75         l[i]=gint(), x=gint(), r[i]=gint(), y=gint();
    76         if(l[i]>r[i]) swap(l[i],r[i]), swap(x,y);
    77         len[i]=sqrt( 1ll*(r[i]-l[i])*(r[i]-l[i])+1ll*(y-x)*(y-x) );
    78         if(l[i]!=r[i]) r[i]--; else p[i]=1;
    79         t[++cnt]=l[i], t[++cnt]=r[i];
    80     } 
    81     sort(t+1,t+cnt+1); cnt=unique(t+1,t+cnt+1)-(t+1);
    82     for(i=1;i<=n;i++) 
    83     {
    84         x=lower_bound(t+1,t+cnt+1,l[i])-t;
    85         y=lower_bound(t+1,t+cnt+1,r[i])-t;
    86         if(p[i]){ l[i]=x*2-1, r[i]=y*2-1; }
    87         else{ l[i]=x*2; r[i]=y*2; }
    88     }
    89     S=0; T=cnt*2+1;
    90     for(i=1;i<=n;i++) e.ae(l[i],r[i]+1,1,len[i]), e.ae(r[i]+1,l[i],0,-len[i]);
    91     for(i=1;i<=cnt*2;i++) e.ae(i,i+1,K,0), e.ae(i+1,i,0,0); e.ae(S,1,K,0); e.ae(1,S,0,0);
    92     printf("%d
    ",EK()); 
    93     return 0;
    94 }
  • 相关阅读:
    WIN7右下角的声音图标不见了
    无法解决 equal to 运算中 "Chinese_PRC_BIN" 和 "Chinese_PRC_CI_AS" 之间的排序规则冲突
    查看表空间信息SQL集合
    Oracle分区表
    Oracle数据库的创建、数据导入导出
    Oracle查询出最最近一次的一条记录
    adb命令
    synergy在Windows和ubuntu 多台PC共享一套键盘鼠标
    git add 之后因为没提交正确文件需要撤销
    make clean-kernel && make kernel
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10291903.html
Copyright © 2020-2023  润新知