LOJ6015「网络流 24 题

来源:互联网 发布:什么平板有windows系统 编辑:程序博客网 时间:2024/06/05 11:22

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

题意:
  由于人类对自然资源的消耗,人们意识到大约在2300年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。

  现有n个太空站位于地球与月球之间,且有 m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船i只可容纳Hi个人。每艘太空船将周期性地停靠一系列的太空站,例如:{1,3,4} 表示该太空船将周期性地停靠太空站 134134134

  每一艘太空船从一个太空站驶往任一太空站耗时均为1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。

  初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。

题解:

  这道题我们可以看得出天与天之间是独立的,而且每次状态的转移都是跨天的,所以我们可以将每一天拆分来看,(据说这叫分层图)每一天我们都有若干个中转站和地月,这样我们就能实现单向建图的目的了。
由于这道题的答案是具有单调性的,所以借助魔术球那道题的经验,我们通过枚举天数,每天新加节点连边跑最大流的方法来找到第一次最大流超过给定的k即可。

  建图方法:

  1. 从源点向每一天的地球链接一条+
  2. 从每一天的月亮向汇点链接一条+
  3. 从上一天的每一个节点向当天的对应节点链接一条+。(因为人们可以留在中转站等一等)。
  4. 针对每一艘飞船,获取其上一天的位置,再获取这一天的位置,在这两个点之间连一条容量为飞船满载人数的流。
  5. 每次新加一天然后跑到最大流超过k就是答案。

  画图理解

# include <bits/stdc++.h># define oo 0x3f3f3f3f# define N 5005class Network  {private :    struct edge  {        int to, w, nxt ;        edge ( ) {        }        edge ( int to, int w, int nxt ) : to ( to ), w ( w ), nxt ( nxt ) {        }      } g [60010 << 1] ;    int head [N], cur [N], ecnt ;    int S, T , dep [N] ;    inline int dfs ( int u, int a )  {        if ( u == T || ! a )  return a ;        int flow = 0, v, f ;        for ( int& i = cur [u] ; i ; i = g [i].nxt )  {            v = g [i].to ;            if ( dep [v] == dep [u] + 1 )  {                f = dfs ( v, std :: min ( g [i].w, a - flow ) ) ;                g [i].w -= f, g [i ^ 1].w += f ;                flow += f ;                if ( a == flow )  return a ;            }        }        if ( ! flow )  dep [u] = -1 ;        return flow ;    }    inline bool bfs ( int S, int T )  {        static std :: queue < int > q ;        memset ( dep, 0, sizeof ( int ) * ( T + 1 ) ) ;        dep [S] = 1 ;        q.push ( S ) ;        while ( ! q.empty ( ) )  {            int u = q.front ( ) ;  q.pop ( ) ;            for ( int i = head [u] ; i ; i = g [i].nxt )  {                int& v = g [i].to ;                if ( g [i].w &&  ! dep [v] )  {                    dep [v] = dep [u] + 1 ;                    q.push ( v ) ;                }            }        }        return dep [T] ;    }public :    Network ( )  {    ecnt = 1 ; }    inline void add_edge ( int u, int v, int w )  {        g [++ ecnt] = edge ( v, w, head [u] ) ;     head [u] = ecnt ;        g [++ ecnt] = edge ( u, 0, head [v] ) ;     head [v] = ecnt ;    }    inline void clear ( )  {        ecnt = 1 ;        memset ( head, 0, sizeof head ) ;    }    inline int dinic ( int S, int T )  {        this -> S = S, this -> T = T ;        static int rt = 0 ;        while ( bfs ( S, T ) )    {            memcpy ( cur, head, sizeof ( int ) * ( T + 1 ) ) ;             rt += dfs ( S, 0x3f3f3f3f ) ;        }        return rt ;    }} Lazer ;int h [31], r [31], s [31] [N] ;int main ( )  {    int n, m, k ;    scanf ( "%d%d%d", & n, & m, & k ) ;    n += 2 ;        for ( int i = 1 ; i <= m ; ++ i )  {        scanf ( "%d%d", h + i, r + i ) ;        for ( int j = 1 ; j <= r [i] ; ++ j )  {            scanf ( "%d", s [i] + j ) ;            s [i] [j] += 2 ;        }    }    const int S = 5001, T = 5002 ;    for ( int ans = 0 ; ; ++ ans )  {        Lazer.add_edge ( S, ans * n + 2, oo ) ;        Lazer.add_edge ( ans * n + 1, T, oo ) ; // moon ;        if ( ans )  {            for ( int i = 1 ; i <= n ; ++ i )  {                Lazer.add_edge ( ( ans - 1 ) * n + i, ans * n + i, oo ) ;            }            for ( int i = 1 ; i <= m ; ++ i )  {                Lazer.add_edge ( ( ans - 1 ) * n + s [i] [( ans - 1 ) % ( r [i] ) + 1], ans * n + s [i] [ans % ( r [i] ) + 1], h [i] ) ;            }            if ( Lazer.dinic ( S, T ) >= k )  {                printf ( "%d\n", ans ) ;                break ;            }            if ( ans > 100 )  {                return puts ( "0" ), 0 ;            }        }    }}
原创粉丝点击