POJ 3686 The Windy's【最小权匹配(神建图啊)】

大意:有n个任务m个机器,告诉你n*m的矩阵表示每个任务在每个机器上完成需要的时间

问所有任务完成的总时间最少?(比如第一个任务在第一分钟完成第二个任务在第二分钟完成   则总时间为1 + 2 = 3

 

分析:

该题自己做的时候没有思路

后来在网上搜题解,感觉建图真是太厉害了

假设最优情况下,个个任务需要的时间分别为a1, a2, a3, ……,an

那么总时间t = n * a1 + (n - 1) * a2 + ……+ 2 * an - 1 + an

也就是说只需要考虑系数就可以了

我们先假设只有一台机器

那么也就是为每个任务的时间选择一个不同的系数

也就是从每个任务向该机器建n条边分别表示系数  边权值为k*cost即可

扩展为m台机器  只要把每个机器拆成n个点就可以了~~

 

代码:

POJ 3686	 The Windy's【最小权匹配(神建图啊)】
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 using namespace std;
  6 
  7 const int maxn = 55;
  8 const int INF = 1000000000;
  9 
 10 int Sx[maxn], Sy[maxn * maxn];
 11 int Lx[maxn], Ly[maxn * maxn];
 12 int Link[maxn * maxn];
 13 int Lix[maxn];
 14 int W[maxn][maxn * maxn];
 15 int n, m;
 16 
 17 bool Find(int i) {
 18     Sx[i] = true;
 19     for(int j = 1; j <= m; j++) {
 20         if(!Sy[j] && Lx[i] + Ly[j] == W[i][j] ) {
 21             Sy[j] = true;
 22             if(Link[j] == 0 || Find(Link[j])) {
 23                 Lix[i] = j;
 24                 Link[j] = i;
 25                 return true;
 26             }
 27         }
 28     }
 29     return false;
 30 }
 31 
 32 int KM() {
 33     for(int i = 1; i <= n; i++) {
 34         Lx[i] = - INF;
 35         for(int j = 1; j <= m; j++) {
 36             Lx[i] = max(Lx[i], W[i][j]);
 37         }
 38     }
 39     memset(Ly, 0, sizeof(Ly));
 40     memset(Link, 0, sizeof(Link));
 41     for(int v = 1; v <= n; v++) {
 42         memset(Sx, 0, sizeof(Sx));
 43         memset(Sy, 0, sizeof(Sy));
 44         while(1) {
 45             if(Find(v)) break;
 46             int dmin = INF;
 47             for(int i = 1; i <= n; i++) {
 48                 if(Sx[i]) {
 49                     for(int j = 1; j <= m; j++) {
 50                         if(!Sy[j] && Lx[i] + Ly[j] - W[i][j] < dmin) {
 51                             dmin = Lx[i] + Ly[j] - W[i][j];
 52                         }
 53                     }
 54                 }
 55             }
 56             for(int i = 1; i <= n; i++) {
 57                 if(Sx[i]) {
 58                     Lx[i] -= dmin;
 59                     Sx[i] = 0;
 60                 }
 61             }
 62             for(int i = 1; i <= m; i++) {
 63                 if(Sy[i]) {
 64                     Ly[i] += dmin;
 65                     Sy[i] = 0;
 66                 }
 67             }
 68         }
 69     }
 70     int sum = 0;
 71     for(int i = 1; i <= n; i++) {
 72         sum += W[i][Lix[i]];
 73     }
 74     return sum;
 75 }
 76 
 77 int mat[maxn][maxn];
 78 int main() {
 79     int t;
 80     scanf("%d",&t);
 81     while(t--) {
 82         scanf("%d %d",&n, &m);
 83         for(int i = 1; i <= n; i++) {
 84             for(int j = 1; j <= m; j++) {
 85                 scanf("%d",&mat[i][j]);
 86             }
 87         }
 88         for(int k = 1; k <= n; k++) {
 89             for(int i = 1; i <= m; i++) {
 90                 for(int j = 1; j <= n; j++) {
 91                     W[k][(i - 1) * n + j] = - mat[k][i] * j;
 92                 }
 93             }
 94         }
 95         m = n * m;
 96         int ans1 = -KM();
 97         double ans = ans1 * 1.0 / n;
 98         printf("%.6f\n",ans);
 99     }
100     return 0;
101 }
View Code

 

POJ 3686 The Windy's【最小权匹配(神建图啊)】

上一篇:开源ext2read代码走读之-在windows下如何判断有几个硬盘设备?


下一篇:ASP.NET关于Login控件使用,LoginView 控件,CreateUserWizard 控件