LOJ6010 「网络流 24 题

来源:互联网 发布:网络安全工程师招聘 编辑:程序博客网 时间:2024/05/21 19:57

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

题意:
  给定一个由 n行数字组成的数字梯形如下图所示。梯形的第一行有m个数字。从梯形的顶部的m个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
  分别遵守以下规则:

  • 从梯形的顶至底的m条路径互不相交;
  • 从梯形的顶至底的m条路径仅在数字结点处相交;
  • 从梯形的顶至底的m条路径允许在数字结点相交或边相交。

      要求输出三个任务的的最大值。

题解:
  坠大费用坠大流(这名字好迷
  第一个任务 TASK1:
  老生常谈的每个点只经过一次拆点建立分层图。即每个点a拆为a1,a2
  建图:

建立超级源点S,和汇点TS向第一层的点分别连一条(Sa1)的弧(其实(Sa2)也是兹磁的),容量为1,0(a2v)。最后一层的点向汇点T连边,a2连向T容量为为1,费用为0
每一个点aa1a2连边,权值为v。对于a走到ba2b1连一条容量为为1,费用为0的边。
如此一来一定保证了每个点只被经过一次,一定有m条不相交不重合的路径。

  对于最大权值,直接跑最大费用最大流就可以了。

  第二个任务 TASK2:

  每个点不要求只经过一次了,但是每条边只能经过一次。
  我们考虑如何在上面的方法改进。

  方法一:不拆点,限制边的流量为1
  方法二:拆点,把a1a2的流量设为+a2b1的连边流量为1,把最后一层的元素到汇点T的流量设为+

  啦啦啦啦

  第三个任务 TASK3:

  乱跑就好了
  我们考虑如何在上面的方法改进。

  方法一:不拆点,限制边的流量为+
  方法二:拆点,把a1a2的流量设为+a2b1的连边流量为+,把最后一层的元素到汇点T的流量设为+

  然后我调了一阵子发现时建图边界GG了,注意S的dis初值要足够大

# 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 5010# define M 16010class  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 ; // big enough !!!            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 n, m ;int a [50] [50] ;int id1 [50] [50], id2 [50] [50] ;void Solve1 ( int S, int T )  {    Lazer.clear ( ) ;    for ( int i = 1 ; i <= m ; ++ i )   Lazer.add_edge ( S, id1 [1] [i], 1, 0 ) ;    for ( int i = 1 ; i <= m + n - 1 ; ++ i )  Lazer.add_edge ( id2 [n] [i], T, 1, 0 ) ;    for ( int i = 1 ; i <= n ; ++ i )        for ( int j = 1 ; j <= i + m - 1 ; ++ j )  {            Lazer.add_edge ( id1 [i] [j], id2 [i] [j], 1, a [i] [j] ) ;            int x = i + 1, y = j + 1 ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id2 [i] [j], id1 [x] [y], 1, 0 ) ;            x = i + 1, y = j ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id2 [i] [j], id1 [x] [y], 1, 0 ) ;        }    printf ( "%d\n", Lazer.mcmf ( S, T ).second ) ;}void Solve2 ( int S, int T )  {    Lazer.clear ( ) ;    for ( int i = 1 ; i <= m ; ++ i )   Lazer.add_edge ( S, id1 [1] [i], 1, a [1] [i] ) ;    for ( int i = 1 ; i <= m + n - 1 ; ++ i )  Lazer.add_edge ( id1 [n] [i], T, oo, 0 ) ;    for ( int i = 1 ; i <= n ; ++ i )        for ( int j = 1 ; j <= i + m - 1 ; ++ j )  {            int x = i + 1, y = j + 1 ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id1 [i] [j], id1 [x] [y], 1, a [x] [y] ) ;            x = i + 1, y = j ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id1 [i] [j], id1 [x] [y], 1, a [x] [y] ) ;        }    printf ( "%d\n", Lazer.mcmf ( S, T ).second ) ;}void Solve3 ( int S, int T )  {    Lazer.clear ( ) ;    for ( int i = 1 ; i <= m ; ++ i )   Lazer.add_edge ( S, id1 [1] [i], 1, a [1] [i] ) ;    for ( int i = 1 ; i <= m + n - 1 ; ++ i )  Lazer.add_edge ( id1 [n] [i], T, oo, 0 ) ;    for ( int i = 1 ; i <= n ; ++ i )        for ( int j = 1 ; j <= i + m - 1 ; ++ j )  {            int x = i + 1, y = j + 1 ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id1 [i] [j], id1 [x] [y], oo, a [x] [y] ) ;            x = i + 1, y = j ;            if ( x <= n && y <= i + m - 1 + 1 )  Lazer.add_edge ( id1 [i] [j], id1 [x] [y], oo, a [x] [y] ) ;        }    printf ( "%d\n", Lazer.mcmf ( S, T ).second ) ;}int main ( )  {//  freopen ( "in.txt", "r", stdin ) ;    int cnt ( 0 ) ;    scanf ( "%d%d", & m, & n ) ;    for ( int i = 1 ; i <= n ; ++ i )        for ( int j = 1 ; j <= i + m - 1 ; ++ j )  {            scanf ( "%d", a [i] + j ) ;            id1 [i] [j] = ++ cnt ;            id2 [i] [j] = ++ cnt ;        }    const int S = cnt + 1, T = cnt + 2 ;    Solve1 ( S, T ) ;    Solve2 ( S, T ) ;    Solve3 ( S, T ) ;    return 0 ;}
原创粉丝点击