LOJ6010 「网络流 24 题
来源:互联网 发布:网络安全工程师招聘 编辑:程序博客网 时间:2024/05/21 19:57
大家都很强, 可与之共勉 。
题意:
给定一个由
分别遵守以下规则:
- 从梯形的顶至底的
m 条路径互不相交; - 从梯形的顶至底的
m 条路径仅在数字结点处相交; 从梯形的顶至底的
m 条路径允许在数字结点相交或边相交。要求输出三个任务的的最大值。
题解:
坠大费用坠大流(这名字好迷)
第一个任务 TASK1:
老生常谈的每个点只经过一次
建图:
建立超级源点
S ,和汇点T ,S 向第一层的点分别连一条(S→a1) 的弧(其实(S→a2) 也是兹磁的),容量为1,费用为0(如果是a2就是权值v) 。最后一层的点向汇点T 连边,a2 连向T 容量为为1 ,费用为0 。
每一个点a ,a1→a2 连边,权值为点权值v 。对于a 走到b ,a2→b1 连一条容量为为1 ,费用为0 的边。
如此一来一定保证了每个点只被经过一次,一定有m 条不相交不重合的路径。
对于最大权值,直接跑最大费用最大流就可以了。
第二个任务 TASK2:
每个点不要求只经过一次了,但是每条边只能经过一次。
我们考虑如何在上面的方法改进。
方法一:不拆点,限制边的流量为
方法二:拆点,把
啦啦啦啦
第三个任务 TASK3:
乱跑就好了
我们考虑如何在上面的方法改进。
方法一:不拆点,限制边的流量为
方法二:拆点,把
然后我调了一阵子发现时建图边界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 ;}
- LOJ6010 「网络流 24 题
- loj6010「网络流 24 题」数字梯形(费用流)
- 【网络流】网络流24题
- [网络流]: 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- 「网络流 24 题」试题库
- 「网络流 24 题」试题库
- LOJ6000 「网络流 24 题
- LOJ6001 「网络流 24 题
- LOJ6002 「网络流 24 题
- LOJ6003 「网络流 24 题
- LOJ6004 「网络流 24 题
- LOJ6005 「网络流 24 题
- LOJ6006「网络流 24 题
- LOJ6007 「网络流 24 题
- ubuntu启动ssh
- C语言读取txt文档中的数据
- 12.加密的病历单
- iptables&firewalld
- 消息机制及应用-同步异步
- LOJ6010 「网络流 24 题
- malloc申请一维动态数组的错误
- 查看手机的app的内存
- 周中训练笔记+HDU1695 GCD 【欧拉函数】【容斥原理】
- Java学习笔记7——集合框架
- python: 大小写转换 内建函数
- 投资比写程序难多了
- python--leetcode538. Convert BST to Greater Tree
- [Leetcode] 508. Most Frequent Subtree Sum 解题报告