题目分析:满足row[i] + col[j]>=G[i][j],且使sum{row[i]}+sum{col[j]}之和最小。
顶标正是KM匹配所维护的对偶变量。所以当求得最大权匹配时顶标之和同时达到最小。
具体参见线性规划。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define For( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define rev( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 505 ; const int INF = 0x3f3f3f3f ; int G[MAXN][MAXN] ; int visx[MAXN] , visy[MAXN] , Time ; int Lx[MAXN] , Ly[MAXN] ; int dx[MAXN] , dy[MAXN] ; int slack ; int n ; int find ( int u ) { visx[u] = Time ; rep ( v , 0 , n ) { if ( visy[v] == Time ) continue ; int tmp = dx[u] + dy[v] - G[u][v] ; if ( !tmp ) { visy[v] = Time ; if ( Ly[v] == -1 || find ( Ly[v] ) ) { Lx[u] = v ; Ly[v] = u ; return 1 ; } } else slack = min ( slack , tmp ) ; } return 0 ; } void KM () { clr ( Lx , -1 ) ; clr ( Ly , -1 ) ; clr ( dx , 0 ) ; clr ( dy , 0 ) ; rep ( i , 0 , n ) rep ( j , 0 , n ) if ( G[i][j] > dx[i] ) dx[i] = G[i][j] ; rep ( i , 0 , n ) { slack = INF ; while ( 1 ) { ++ Time ; if ( find ( i ) ) break ; rep ( i , 0 , n ) if ( visx[i] == Time ) dx[i] -= slack ; rep ( i , 0 , n ) if ( visy[i] == Time ) dy[i] += slack ; } } } void solve () { int res = 0 ; rep ( i , 0 , n ) rep ( j , 0 , n ) scanf ( "%d" , &G[i][j] ) ; KM () ; rep ( i , 0 , n ) { res += dx[i] ; printf ( "%d%c" , dx[i] , i < n - 1 ? ' ' : '\n' ) ; } rep ( i , 0 , n ) { res += dy[i] ; printf ( "%d%c" , dy[i] , i < n - 1 ? ' ' : '\n' ) ; } printf ( "%d\n" , res ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }