POJ 3686 The Windy's KM算法
2012-08-11 16:20
471 查看
这题的建图实在是太神了
假设某个机器处理了k个玩具,那么对于这些玩具,有两种时间,一种是真正处理的时间,一种是等待的时间,等待的时间就是之前所有处理的玩具的时间,
假设这k个玩具真正用在加工的时间分为a1,a2,a3...ak, 那么每个玩具实际的时间是加工的时间+等待时间,分别为
a1, a1+a2, a1+a2+a3.......a1+a2+...ak
求和之后变为 a1 *k + a2 * (k - 1) + a3 * (k - 2).... + ak
这时就发现,每个玩具之间的实际时间可以分开来算 然后求和了。
因为对每个机器,最多可以处理n个玩具,所以可以拆成n个点,1~n分别代表某个玩具在这个机器上倒数第几个被加工的
所以我们对于每个玩具i,机器j中拆的每个点k,连接一条z[i][j]*k权值的边。
然后求最小权匹配即可
假设某个机器处理了k个玩具,那么对于这些玩具,有两种时间,一种是真正处理的时间,一种是等待的时间,等待的时间就是之前所有处理的玩具的时间,
假设这k个玩具真正用在加工的时间分为a1,a2,a3...ak, 那么每个玩具实际的时间是加工的时间+等待时间,分别为
a1, a1+a2, a1+a2+a3.......a1+a2+...ak
求和之后变为 a1 *k + a2 * (k - 1) + a3 * (k - 2).... + ak
这时就发现,每个玩具之间的实际时间可以分开来算 然后求和了。
因为对每个机器,最多可以处理n个玩具,所以可以拆成n个点,1~n分别代表某个玩具在这个机器上倒数第几个被加工的
所以我们对于每个玩具i,机器j中拆的每个点k,连接一条z[i][j]*k权值的边。
然后求最小权匹配即可
#include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <queue> #include <map> #include <set> #define eps 1e-5 #define MAXN 55 #define MAXM 55555 #define INF 100000007 using namespace std; int n, m, ny, nx; int w[MAXN][2555]; int lx[MAXN], ly[2555]; int linky[2555]; int visx[MAXN], visy[2555]; int slack[2555]; bool find(int x) { visx[x] = 1; for(int y = 1; y <= ny; y++) { if(visy[y]) continue; int t = lx[x] + ly[y] - w[x][y]; if(t == 0) { visy[y] = 1; if(linky[y] == -1 || find(linky[y])) { linky[y] = x; return true; } } else if(slack[y] > t) slack[y] = t; } return false; } int KM() { memset(linky, -1, sizeof(linky)); for(int i = 1; i <= nx; i++) lx[i] = -INF; memset(ly, 0, sizeof(ly)); for(int i = 1; i <= nx; i++) for(int j = 1; j <= ny; j++) if(w[i][j] > lx[i]) lx[i] = w[i][j]; for(int x = 1; x <= nx; x++) { for(int i = 1; i <= ny; i++) slack[i] = INF; while(true) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if(find(x)) break; int d = INF; for(int i = 1; i <= ny; i++) if(!visy[i]) d = min(d, slack[i]); if(d == INF) return -1; for(int i = 1; i <= nx; i++) if(visx[i]) lx[i] -=d; for(int i = 1; i <= ny; i++) if(visy[i]) ly[i] += d; else slack[i] -= d; } } int tp = 0; for(int i = 1; i <= ny; i++) if(linky[i] != -1) tp += w[linky[i]][i] - 5000000; return -tp; } int a[MAXN][MAXN]; int main() { int T; scanf("%d", &T); while(T--) { memset(w, 0, sizeof(w)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &a[i][j]); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) for(int k = 1; k <= n; k++) w[i][(j - 1) * n + k] = 5000000 - a[i][j] * k; nx = n; ny = n * m; double ans = 1.0 * KM() / n; printf("%f\n", ans); } return 0; }
相关文章推荐
- POJ_3686_The Windy's(最小费用流)
- [ACM] POJ 3686 The Windy's (二分图最小权匹配,KM算法,特殊建图)
- POJ 3686 The Windy's 指派问题 拆点
- poj 3686 The Windy's 二分图最小权和匹配KM
- poj 3686 The Windy's(最小费用最大流)
- 【POJ 3686】The Windy's(KM算法)
- The Windy's (poj 3686 最小费用最大流 建图经典)
- poj 3686 The Windy's(最小权值和)
- POJ 3686 The Windy's & HDU 3718 Similarity
- poj 3686 The Windy's 二分匹配 KM算法求最小权匹配
- The Windy's - POJ 3686 KM算法
- POJ-3686-TheWindy's
- poj 2388 Who's in the Middle
- POJ 2388 Who's in the Middle
- POJ 2965 The Pilots Brothers' refrigerator
- POJ 2965 The Pilots Brothers' refrigerator 搜索+枚举
- poj2965 The Pilots Brothers' refrigerator
- poj 2965 The Pilots Brothers' refrigerator
- poj 2965 The Pilots Brothers' refrigerator
- POJ 2965 The Pilots Brothers' refrigerator 枚举