uva 11383 Golden Tiger Claw

题目大意:给定一个N×N的矩阵,每一个格子里都有一个正整数w(i,j)。你的任务是给每行确定一个整数row(i), 每列也确定一个整数col(i),使得对于格子(i,j)w(i,j)<=row(i)+col(j)。全部row(i)col(j)的总和最小。

解题思路:KM算法。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;

const int N = 5000;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n;
int W[N][N];
int Lx[N], Ly[N];
int left[N];
bool S[N], T[N];

bool match(int i) {
    S[i] = true;
    for (int j = 1; j <= n; j++) {
        if (Lx[i] + Ly[j] == W[i][j] && !T[j]) {
            T[j] = true;
            if (!left[j] || match(left[j])) {
                left[j] = i;
                return true;
            }
        }   
    }
    return false;
}

void update() {
    int a = INF; 
    for (int i = 1; i <= n; i++) {
        if (!S[i]) continue;
        for (int j = 1; j <= n; j++) {
            if (T[j]) continue; 
            a = min(a, Lx[i] + Ly[j] - W[i][j]);
        }
    }
    for (int i = 1; i <= n; i++) {
        if (S[i]) Lx[i] -= a;
        if (T[i]) Ly[i] += a;
    }
}

void KM() {
    //初始时为了使Lx[i]+Ly[j]>=W[i, j]恒成立,令Lx[i]为全部与顶点Xi关联的边的最大权,Ly[j]=0
    for (int i = 1; i <= n; i++) {
        left[i] = Lx[i] = Ly[i] = 0;    
        for (int j = 1; j <= n; j++) {
            Lx[i] = max(Lx[i], W[i][j]);    
        }
    }
    for (int i = 1; i <= n; i++) {
        while (1) {
            for (int j = 1; j <= n; j++) S[j] = T[j] = 0;
            if (match(i)) break;
            else update();
        }   
    }
}

void input() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            scanf("%d", &W[i][j]);  
        }   
    }
}

int main() {
    while (scanf("%d", &n) != EOF) {
        input();
        KM();
        int sum = Lx[1];
        printf("%d", Lx[1]);
        for (int i = 2; i <= n; i++) {
            printf(" %d ", Lx[i]);  
            sum += Lx[i];
        }
        puts("");
        printf("%d", Ly[1]);
        sum += Ly[1];
        for (int i = 2; i <= n; i++) {
            printf(" %d", Ly[i]);   
            sum += Ly[i];
        }
        printf("\n%d\n", sum);
    }
    return 0;
}