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 }

 

posted @ 2018-08-14 23:11  iamunstoppable  阅读(407)  评论(0编辑  收藏  举报