hdu6346: 整数规划
读完题目就想费用流和单纯形去了。
实际上,我们发现这个题目的求解问题。
其实就是KM算法求二分图最小权匹配的做法,跑个KM就行了。
然后这个题写递归的KM根本过不了,得用非递归的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define inf 1000000000000ll 5 inline int read() { 6 char ch = getchar(); int x = 0, f = 1; 7 while(ch < '0' || ch > '9') { 8 if(ch == '-') f = -1; 9 ch = getchar(); 10 } 11 while('0' <= ch && ch <= '9') { 12 x = x * 10 + ch - '0'; 13 ch = getchar(); 14 } 15 return x * f; 16 } 17 namespace KM{ 18 #define M 410 19 int n; 20 LL A[M], B[M], mn[M]; 21 int w[M][M], lk[M], way[M]; 22 bool vis[M]; 23 inline void km(){ 24 memset(lk, -1, sizeof(lk)); 25 for(int x = 1; x <= n; ++ x) { 26 lk[0] = x; 27 int j0 = 0; 28 memset(vis, 0, sizeof(vis)); 29 memset(mn, 0x3f, sizeof(mn)); 30 do{ 31 vis[j0] = true; 32 int i0 = lk[j0], j1; 33 LL num = inf; 34 for(int j = 1; j <= n; ++ j){ 35 if(!vis[j]){ 36 LL t = A[i0] + B[j] - w[i0][j]; 37 if(t < mn[j]) mn[j] = t, way[j] = j0; 38 if(mn[j] < num) num = mn[j], j1 = j; 39 } 40 } 41 for(int j = 0; j <= n; ++ j){ 42 if(vis[j]) A[lk[j]] -= num, B[j] += num; 43 else mn[j] -= num; 44 } 45 //cerr << x <<endl; 46 j0 = j1; 47 } while(~lk[j0]); 48 do{ 49 int j1 = way[j0]; 50 lk[j0] = lk[j1]; 51 j0 = j1; 52 } while(j0); 53 } 54 } 55 inline LL getsum(){ 56 LL ret = 0; 57 for(int i = 1; i <= n; ++ i) ret += A[i], ret += B[i]; 58 return ret; 59 } 60 } 61 signed main() { 62 //int TT = clock(); 63 int T; 64 scanf("%d", &T); 65 for(int Ca = 1; Ca <= T; ++ Ca) { 66 scanf("%d", &KM::n); 67 for(int i = 1; i <= KM::n; ++ i) { 68 for(int j = 1; j <= KM::n; ++ j) { 69 KM::w[i][j] = read(); 70 KM::w[i][j] *= -1; 71 } 72 } 73 //cerr << 2333 << endl; 74 KM::km(); 75 printf("Case #%d: %I64d\n", Ca, -KM::getsum()); 76 } 77 //cerr << clock() - TT; 78 }