https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2378
大致题意:
500*500带权格子,每行每列要确定一个值,使row[i]+col[j] >= val[i][j],要使所有row值和col值的和最小
输出每行的row[i],和每列的col[i]
大致思路:
吐槽一句,总是往网络流方向想= =,居然考察了km的原理,本来km原理就没仔细学
KM执行的过程始终满足lx[i] + ly[j] >= Edge(i,j)
最后找到完美匹配也就是 满足lx[i]+ly[j] == Edge(i,j)的可行边的集合,显然对这些可行边来说,这n对lx[i]+ly[j]的值已经达到最小了,
也就是sigma(lx[i]) + sigma(ly[i])达到最小值,等于这些可行边的边权和,也就是完美匹配的最大权值
// Accepted C++11 0.120 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <string> #include <vector> #include <cstdio> #include <ctime> #include <bitset> #include <algorithm> #define SZ(x) ((int)(x).size()) #define ALL(v) (v).begin(), (v).end() #define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i) #define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i) #define REP(i,n) for ( int i=1; i<=int(n); i++ ) #define rep(i,n) for ( int i=0; i<int(n); i++ ) using namespace std; typedef long long ll; #define X first #define Y second typedef pair<ll,ll> pii; template <class T> inline bool RD(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } template <class T> inline void PT(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) pt(x / 10); putchar(x % 10 + '0'); } const int N = 500+10; const int inf = 0x3f3f3f3f; int n; int mp[N][N]; int link[N]; int lx[N],ly[N]; //y中各点匹配状态,x,y中的点标号 int sla[N]; bool visx[N],visy[N]; bool DFS(int x){ visx[x] = true; REP(y,n){ if(visy[y])continue; int tmp = lx[x] + ly[y] - mp[x][y]; if(tmp == 0){ visy[y] = true; if(link[y] == -1 || DFS(link[y])){ link[y] = x; return true; } } else if(sla[y] > tmp) sla[y] = tmp; } return false; } int KM(){ memset(link,-1,sizeof(link)); memset(ly,0,sizeof(ly)); REP(i,n){ lx[i] = -inf; REP(j,n) lx[i] = max(lx[i],mp[i][j]); } REP(x,n){ REP(i,n) sla[i] = inf; while(true){ memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(DFS(x)) break; int d = inf; REP(i,n) if(!visy[i]) d = min(d,sla[i]); REP(i,n){ if(visx[i]) lx[i] -= d; if(visy[i])ly[i] += d; else sla[i] -= d; } } } int res = 0; REP(i,n) if(link[i] != -1) res += mp[link[i]][i]; return res; } int main(){ while(~scanf("%d",&n)){ REP(x,n) REP(y,n) RD(mp[x][y]); int ans = KM(); REP(i,n) printf("%d%c",lx[i],i == n?'\n':' '); REP(i,n) printf("%d%c",ly[i],i == n?'\n':' '); printf("%d\n",ans); } }