题干:
粘贴不过来。。。
题目大意:
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;
}