【ACDream】1355 Domino in Casino 费用流

来源:互联网 发布:端口类型以太网 编辑:程序博客网 时间:2024/06/07 00:29

传送门:【ACDream】1355 Domino in Casino


题目分析:费用流水题(前提是能看出来)。将矩阵黑白染色。黑色结点和源点建边,容量1,费用0。白色结点和汇点建边,容量1,费用0。黑色结点向相邻的白色结点建边,容量1,费用为两结点内权值的乘积的相反数。再建立超级源汇,超级源点向源点建边,容量k,费用0。汇点向超级汇点建边,容量k,费用0。最后跑一遍最小费用最大流即可。费用的相反数即答案。

就是二分图上的匹配问题,限制就是至多只能有K对匹配,所以用费用流求解。


代码如下:


#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define clr( a , x ) memset ( a , x , sizeof a )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 2005 ;const int MAXQ = 1000005 ;const int MAXE = 1000005 ;const int INF = 0x3f3f3f3f ;struct Edge {int v , c , w , n ;Edge () {}Edge ( int v , int c , int w , int n ) : v ( v ) , c ( c ) , w ( w ) , n ( n ) {}} E[MAXE] ;int H[MAXN] , cntE ;int d[MAXN] , cur[MAXN] , cap[MAXN] ;int vis[MAXN] , Time ;int Q[MAXQ] , head , tail ;int ss , tt ;int s , t ;int flow ;int cost ;int n , m , k ;int a[17][105] ;void clear () {cntE = 0 ;clr ( H , -1 ) ;}void addedge ( int u , int v , int c , int w ) {E[cntE] = Edge ( v , c , +w , H[u] ) ;H[u] = cntE ++ ;E[cntE] = Edge ( u , 0 , -w , H[v] ) ;H[v] = cntE ++ ;}int spfa () {head = tail = 0 ;clr ( d , INF ) ;++ Time ;d[ss] = 0 ;cap[ss] = INF ;cur[ss] = -1 ;Q[tail ++] = ss ;while ( head != tail ) {int u = Q[head ++] ;vis[u] = Time - 1 ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v , c = E[i].c , w = E[i].w ;if ( c && d[v] > d[u] + w ) {d[v] = d[u] + w ;cap[v] = min ( cap[u] , c ) ;cur[v] = i ;if ( vis[v] != Time ) {vis[v] = Time ;Q[tail ++] = v ;}}}}if ( d[tt] == INF ) return 0 ;cost += d[tt] * cap[tt] ;flow += cap[tt] ;for ( int i = cur[tt] ; ~i ; i = cur[E[i ^ 1].v] ) {E[i].c -= cap[tt] ;E[i ^ 1].c += cap[tt] ;}return 1 ;}int mcmf () {flow = cost = 0 ;while ( spfa () ) ;return cost ;}void solve () {clear () ;s = n * m ;t = s + 1 ;ss = t + 1 ;tt = ss + 1 ;addedge ( ss , s , k , 0 ) ;addedge ( t , tt , k , 0 ) ;rep ( i , 0 , n ) rep ( j , 0 , m ) scanf ( "%d" , &a[i][j] ) ;rep ( i , 0 , n ) rep ( j , 0 , m ) {int ij = i * m + j ;if ( ( i + j ) & 1 ) {addedge ( s , ij , 1 , 0 ) ;if ( i < n - 1 ) addedge ( ij , ij + m , 1 , - a[i][j] * a[i + 1][j] ) ;if ( j < m - 1 ) addedge ( ij , ij + 1 , 1 , - a[i][j] * a[i][j + 1] ) ;if ( i ) addedge ( ij , ij - m , 1 , - a[i][j] * a[i - 1][j] ) ;if ( j ) addedge ( ij , ij - 1 , 1 , - a[i][j] * a[i][j - 1] ) ;} else addedge ( ij , t , 1 , 0 ) ;}printf ( "%d\n" , -mcmf () ) ;}int main () {clr ( vis , 0 ) ;Time = 0 ;while ( ~scanf ( "%d%d%d" , &n , &m , &k ) ) solve () ;return 0 ;}


0 0
原创粉丝点击