LOJ6014「网络流 24 题 - 15」最长 k 可重区间集 坠大权不相交路径 坠大费用坠大流

大家都很强, 可与之共勉 。

题意:
  给定实直线 L n个开区间组成的集合 I ,和一个正整数k,试设计一个算法,从开区间集合 I 中选取出开区间集合 SI,使得在实直线 L 的任何一点x S 中包含点x的开区间个数不超过 k 。且 zS|z|达到最大。这样的集合 S 称为开区间集合I的最长 k 可重区间集。zS|z|称为最长 k 可重区间集的长度。
  对于给定的开区间集合I和正整数 k ,计算开区间集合I的最长 k 可重区间集的长度。

题解:

  把答案看作是k条路径的权值和坠大,路径不存在边相交(此处的边就是区间)。
  既然是点可以重合,那么可以不拆点(其实拆点也可以的)。
  因为是 k 条路径,所以从源点到一号点连一条容量为k,费用为 0 的边。最后一个点向汇点,连一条容量为x(x[k,+)),的边,之后对于 lr,ri 之间连一条容量为 1 ,费用为长度的边。然后我们要保证可以有区间不被选到(跳过这个区间),每个点向下一个点连一条容量为+(其实大于等于 k 就够了),然后直接跑最大费用最大流。最后一定满足条件。最后的最大流一定是k

  画画图很好理解的

# include <bits/stdc++.h>

template < class T >  inline bool chkmax ( T& d, const T& x )  {  return d < x ? ( d = x ), 1 : 0 ;  }
template < class T >  inline bool chkmin ( T& d, const T& x )  {  return d > x ? ( d = x ), 1 : 0 ;  }

# define oo 0x3f3f3f3f

# define N 1050
# define M 5050

class MaxCostMaxFlow  {
    private :
        struct edge  {
            int to, nxt, w, cost ;
        } g [M << 1] ;

        int S, T ;
        int head [N], dis [N], pre [N], ecnt ;

        inline bool spfa ( int S, int T )  {
            static std :: bitset < N > inq ;
            static std :: deque < int > Q ;
            inq.reset ( ) ; Q.clear ( ) ;
            memset ( pre, 0, sizeof ( int ) * ( T + 1 ) ) ;
            memset ( dis, -1, sizeof ( int ) * ( T + 1 ) ) ;
            Q.push_front ( S ) ;
            inq [S] = 1 ;
            dis [S] = 0x3f3f3f3f ; 
            while ( ! Q.empty ( ) )  {
                int u = Q.front ( ) ; Q.pop_front ( ) ;
                inq [u] = 0 ;
                for ( int i = head [u] ; i ; i = g [i].nxt )  {
                    int& v = g [i].to ;
                    if ( g [i].w && chkmax ( dis [v], dis [u] + g [i].cost ) )  {
                        pre [v] = i ;
                        if ( ! inq [v] )  {
                            ( Q.empty ( ) || dis [v] > dis [Q.front ( )] ) ? Q.push_front ( v ) : Q.push_back ( v ) ;
                            inq [v] = 1 ;
                        }
                    }
                }
            }
            return ( bool ) pre [T] ;
        }
    public :
        MaxCostMaxFlow ( )  {  ecnt = 1 ; memset ( head, 0, sizeof head ) ;  }

        inline void clear ( )  {
            ecnt = 1 ; memset ( head, 0, sizeof head ) ;
        }

        inline void add_edge ( int u, int v, int w, int cost )  {
            g [++ ecnt] = ( edge )  {  v, head [u], w, cost } ; head [u] = ecnt ;
            g [++ ecnt] = ( edge )  {  u, head [v], 0, -cost } ; head [v] = ecnt ;
        }

        std :: pair < int, int > mcmf ( int S, int T )  {
            this -> S = S, this -> T = T ;
            int flow = 0, cost = 0, x ;
            while ( spfa ( S, T ) )  {
                x = oo ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  chkmin ( x, g [i].w ) ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  {
                    g [i].w -= x, g [i ^ 1].w += x ;
                    cost += x * g [i].cost ;
                }

                flow += x ;
            }
            return std :: make_pair ( flow, cost ) ;
        }
} Lazer ;

int dust [N] ;
int l [N], r [N], val [N] ;

# undef N
# undef M

int main ( )  {
    int n, k ;
    scanf ( "%d%d", & n, & k ) ;
    const int S = 2 * n + 1, T = 2 * n + 2 ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        scanf ( "%d%d", l + i, r + i ) ;
        if ( l [i] > r [i] )  std :: swap ( l [i], r [i] ) ;
        dust [( i << 1 ) - 1] = l [i], dust [i << 1] = r [i] ;
        val [i] = ( r [i] - l [i] ) ;
    }
    std :: sort ( dust + 1, dust + n + n + 1 ) ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        l [i] = std :: lower_bound ( dust + 1, dust + 1 + n + n, l [i] ) - dust ;
        r [i] = std :: lower_bound ( dust + 1, dust + 1 + n + n, r [i] ) - dust ;
    }
    Lazer.add_edge ( S, 1, k, 0 ), Lazer.add_edge ( 2 * n, T, k, 0 ) ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        Lazer.add_edge ( l [i], r [i], 1, val [i] ) ;
    }
    for ( int i = 1 ; i < 2 * n ; ++ i )  {
        Lazer.add_edge ( i, i + 1, oo, 0 ) ;
    }
    printf ( "%d\n", Lazer.mcmf ( S, T ).second ) ;
    return 0 ;
}

  还有一种建图(边数复杂度是一样的):

# include <bits/stdc++.h>

template < class T >  inline bool chkmax ( T& d, const T& x )  {  return d < x ? ( d = x ), 1 : 0 ;  }
template < class T >  inline bool chkmin ( T& d, const T& x )  {  return d > x ? ( d = x ), 1 : 0 ;  }

# define oo 0x3f3f3f3f

# define N 1050
# define M 5050

class MaxCostMaxFlow  {
    private :
        struct edge  {
            int to, nxt, w, cost ;
        } g [M << 1] ;

        int S, T ;
        int head [N], dis [N], pre [N], ecnt ;

        inline bool spfa ( int S, int T )  {
            static std :: bitset < N > inq ;
            static std :: deque < int > Q ;
            inq.reset ( ) ; Q.clear ( ) ;
            memset ( pre, 0, sizeof ( int ) * ( T + 1 ) ) ;
            memset ( dis, -1, sizeof ( int ) * ( T + 1 ) ) ;
            Q.push_front ( S ) ;
            inq [S] = 1 ;
            dis [S] = 0x3f3f3f3f ;
            while ( ! Q.empty ( ) )  {
                int u = Q.front ( ) ; Q.pop_front ( ) ;
                inq [u] = 0 ;
                for ( int i = head [u] ; i ; i = g [i].nxt )  {
                    int& v = g [i].to ;
                    if ( g [i].w && chkmax ( dis [v], dis [u] + g [i].cost ) )  {
                        pre [v] = i ;
                        if ( ! inq [v] )  {
                            ( Q.empty ( ) || dis [v] > dis [Q.front ( )] ) ? Q.push_front ( v ) : Q.push_back ( v ) ;
                            inq [v] = 1 ;
                        }
                    }
                }
            }
            return ( bool ) pre [T] ;
        }
    public :
        MaxCostMaxFlow ( )  {  ecnt = 1 ; memset ( head, 0, sizeof head ) ;  }

        inline void clear ( )  {
            ecnt = 1 ; memset ( head, 0, sizeof head ) ;
        }

        inline void add_edge ( int u, int v, int w, int cost )  {
            g [++ ecnt] = ( edge )  {  v, head [u], w, cost } ; head [u] = ecnt ;
            g [++ ecnt] = ( edge )  {  u, head [v], 0, -cost } ; head [v] = ecnt ;
        }

        std :: pair < int, int > mcmf ( int S, int T )  {
            this -> S = S, this -> T = T ;
            int flow = 0, cost = 0, x ;
            while ( spfa ( S, T ) )  {
                x = oo ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  chkmin ( x, g [i].w ) ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  {
                    g [i].w -= x, g [i ^ 1].w += x ;
                    cost += x * g [i].cost ;
                }

                flow += x ;
            }
            return std :: make_pair ( flow, cost ) ;
        }
} Lazer ;

int dust [N] ;
int l [N], r [N], val [N] ;

# undef N
# undef M

int main ( )  {
    int n, k ;
    scanf ( "%d%d", & n, & k ) ;
    const int S = 2 * n + 5, T = 2 * n + 6 ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        scanf ( "%d%d", l + i, r + i ) ;
        if ( l [i] > r [i] )  std :: swap ( l [i], r [i] ) ;
        dust [( i << 1 ) - 1] = l [i], dust [i << 1] = r [i] ;
        val [i] = ( r [i] - l [i] ) ;
    }
    std :: sort ( dust + 1, dust + n + n + 1 ) ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        l [i] = std :: lower_bound ( dust + 1, dust + 1 + n + n, l [i] ) - dust ;
        r [i] = std :: lower_bound ( dust + 1, dust + 1 + n + n, r [i] ) - dust ;
    }
    const int S1 = 2 * n + 1, T1 = 2 * n + 2 ;
    Lazer.add_edge ( S, S1, k, 0 ), Lazer.add_edge ( T1, T, k, 0 ) ;
    for ( int i = 1 ; i <= 2 * n ; ++ i )  {
        Lazer.add_edge ( S1, i, 1, 0 ), Lazer.add_edge ( i, T1, 1, 0 ) ;
    }
    for ( int i = 1 ; i <= n ; ++ i )  {
        Lazer.add_edge ( l [i], r [i], 1, val [i] ) ;
    }
    for ( int i = 1 ; i < 2 * n ; ++ i )  {
        Lazer.add_edge ( i, i + 1, oo, 0 ) ;
    }
    printf ( "%d\n", Lazer.mcmf ( S, T ).second ) ;
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值