题干:

   粘贴不过来。。。

题目大意:

    500*500带权格子,每行每列要确定一个值,使row[i]+col[j] >= val[i][j],要使所有row值和col值的和最小

输出每行的row[i],和每列的col[i]。

解题报告:

    跑一边KM,自带着就把我们需要的期望值给求出来了。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
 
using namespace std;
const int MAXN = 505;
const int INF = 0x3f3f3f3f;
int line[MAXN][MAXN];
int ex[MAXN],ey[MAXN];
bool visx[MAXN];
bool visy[MAXN];
int nxt[MAXN];
int slack[MAXN];
int N;
bool dfs(int x) {
	visx[x] = 1;
	for (int y = 1; y <= N; ++y) {
		if (visy[y]) continue; 
		int tmp = ex[x] + ey[y] - line[x][y];
		if (tmp == 0) {
			visy[y] = 1;
			if (nxt[y] == -1 || dfs( nxt[y] )) {
				nxt[y] = x;
				return 1;
			}
		} 
		else if(slack[y] > tmp) slack[y] = tmp;
	}
	return 0;
}
int KM() {
	memset(nxt, -1, sizeof nxt);
	memset(ey, 0, sizeof ey);
	for (int i = 1; i <= N; ++i) {
		ex[i] = line[i][1];
		for (int j = 2; j <= N; ++j) {
			ex[i] = max(ex[i], line[i][j]);
		}
	}
	for (int i = 1; i <= N; ++i) {
		fill(slack, slack + N + 1, INF);
		while (1) {
			memset(visx, 0, sizeof visx);
			memset(visy, 0, sizeof visy);
			if (dfs(i)) break;
			int d = INF;
			for (int j = 1; j <= N; ++j)
				if (!visy[j]) d = min(d, slack[j]);
			for (int j = 1; j <= N; ++j) {
				if (visx[j]) ex[j] -= d;
				if (visy[j]) ey[j] += d;
				else slack[j] -= d;
			}
		}
	}
	int res = 0;
	for (int i = 1; i <= N; ++i) res += line[ nxt[i] ][i];
	return res;
}
int main() {
	while (~scanf("%d",&N)) {
		for (int i = 1; i <= N; ++i)
			for (int j = 1; j <= N; ++j)
				scanf("%d", &line[i][j]);
		int ans = KM();
		for(int i = 1; i<=N; i++) {
			printf("%d%c",ex[i],i == N ? '\n' : ' ');
		}
		for(int i = 1; i<=N; i++) {
			printf("%d%c",ey[i],i == N ? '\n' : ' ');
		}
		printf("%d\n",ans);
	}
	return 0;
}