poj - 3686 The Windy's (KM算法)

题意:n个订单和m个生产车间,每个订单在不同的车间生产所需要的时间不一样,并且每个订单只能在同一个车间中完成,直到这个车间完成这个订单就可以生产下一个订单.现在需要求完成n个订单的平均时间最少是多少.(每个订单的单独时间之和/n,包括等待时间)。

主要是建图,考虑第i个订单在第j个车间倒数第k个被生产,那么第i个订单在第j个区间所花费的时间为k*mat[i][j].

每个区间最多生产n个订单,那么就可以把n*m的图转化成n*(n*m)的图进而用km算法求最小权值。

所以把每个权值取反进而求最大权匹配,但是为什么不能直接求最小权匹配还是没想清楚.

注意G++用%f输出,否则wa.

参考:http://www.tuicool.com/articles/jmYNryf

 1 #include<iostream>
 2 #define max(a,b) ((a)>(b)?(a):(b))
 3 #define min(a,b) ((a)<(b)?(a):(b))
 4 using namespace std;
 5 const int nMax = 52;
 6 const int mMax = 2502;
 7 const int inf = 99999999;
 8  
 9 int n, m;                     //  n为X集合顶点数量,m为Y集合顶点数量。(1~n和1~m)
10 int map[nMax][mMax];          //  map[i][j]:记录X集合中的i到Y集合中的j所需的费用。
11 int lx[nMax], ly[mMax];
12 int link[mMax];
13 bool x[nMax], y[mMax];
14  
15 bool dfs(int u){              //  判断能否找到最大完全匹配。
16     x[u] = true;
17     for(int v = 1; v <= m; v ++)
18         if(!y[v] && lx[u] + ly[v] == map[u][v]){
19             y[v] = true;
20             if(!link[v] || dfs(link[v])){
21                 link[v] = u;
22                 return true;
23             }
24         }
25     return false;
26 }
27  
28 int KM(){                     //  KM算法。
29     int i, j, k, mi;
30     for(i = 1; i <= n; i ++)
31         for(lx[i] = -inf, j = 1; j <= m; j ++)
32             lx[i] = max(lx[i], map[i][j]);
33     memset(ly, 0, sizeof(ly));
34     memset(link, 0, sizeof(link));
35     for(k = 1; k <= n; k ++){
36         while(1){
37             memset(x, 0, sizeof(x));
38             memset(y, 0, sizeof(y));
39             if(dfs(k)) break;
40             mi = inf;
41             for(i = 1; i <= n; i ++)
42                 if(x[i])
43                     for(j = 1; j <= m; j ++)
44                         if(!y[j])
45                             mi = min(mi, lx[i] + ly[j] - map[i][j]);
46             for(i = 1; i <= n; i ++) if(x[i]) lx[i] -= mi;
47             for(i = 1; i <= m; i ++) if(y[i]) ly[i] += mi;
48         }
49     }
50     int ans = 0;
51     for(i = 1; i <= m; i ++)
52         if(link[i] > 0)
53             ans += map[link[i]][i];
54     return ans;
55 }
56  
57 int main(){
58     int t, N, M, i, j, k, mat[nMax][nMax];
59     scanf("%d", &t);
60     while(t --){
61         scanf("%d%d", &N, &M);
62         for(i = 1; i <= N; i ++)
63             for(j = 1; j <= M; j ++)
64                 scanf("%d", &mat[i][j]);
65         n = N, m = N * M;
66         for(i = 1; i <= N; i ++)         //  KM算法是求最大权,故这里存负数,最后取反求最小权。
67             for(j = 1; j <= N; j ++)
68                 for(k = 1; k <= M; k ++){
69                     map[i][(k-1)*N+j] = -j*mat[i][k];
70                     //cout << i << ' ' << (k-1)*N+j << ' ' << j*mat[i][k] << endl;
71                 }
72         double ans = 1.0*(-KM())/N;      //  精度必须取double才AC。
73         printf("%.6f\n", ans);
74     }
75     return 0;
76 }

这题还可以用费用流来解决.不过效率没有KM高.

初始源点和每个订单相连,每个车间拆成n*m个车间,然后和汇点相连.然后和km考虑的一样在订单和车间之间连边.

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn = 2550;
 7 const int INF = 1e9;
 8 struct edge{
 9     int to,next;
10     int cap,flow,cost;
11 }e[maxn*maxn];
12 int n,m;
13 int head[maxn],sz,res;
14 bool inq[maxn];
15 int p[maxn],d[maxn],a[maxn];
16 void addedge(int u,int v,int cap,int cost){
17     e[sz].to = v;e[sz].next = head[u];
18     e[sz].cap = cap;e[sz].flow = 0;e[sz].cost = cost;
19     head[u] = sz ++;
20     e[sz].to = u;e[sz].next = head[v];
21     e[sz].cap = 0;e[sz].flow = 0;e[sz].cost = -cost;
22     head[v] = sz ++;
23 }
24 void init(){
25     memset(head,-1,sizeof(head));
26     sz = 0;
27 }
28 queue<int> Q;
29 int SPFA(int s,int t){
30     memset(inq,0,sizeof(inq));
31     for(int i = 0 ; i <= t ; i ++) d[i] = INF;
32     inq[s] = 1;d[s] = 0;p[s] = -1;
33     a[s] = INF;
34     Q.push(s);
35     while(!Q.empty()){
36         int u = Q.front();Q.pop();
37         inq[u] = 0;
38         for(int i = head[u] ; i != -1 ; i = e[i].next){
39             int v = e[i].to;
40             if(e[i].cap - e[i].flow > 0 && e[i].cost + d[u] < d[v]){
41                 d[v] = d[u] + e[i].cost;
42                 a[v] = min(e[i].cap - e[i].flow,a[u]);
43                 p[v] = i;
44                 if(!inq[v]){
45                     inq[v] = 1;
46                     Q.push(v);
47                 }
48             }
49         }
50     }
51     int u = t;
52     if(d[t] == INF) return 0;
53     res += d[t] * a[t];
54     while(u != s){
55         e[ p[u] ].flow += a[t];
56         e[ p[u] ^ 1 ].flow -= a[t];
57         u = e[ p[u] ^ 1 ].to;
58     }
59     return 1;
60 }
61 
62 void MCMF(int s,int t){
63     res = 0;
64     while(SPFA(s,t));
65     printf("%.6f\n",res*1.0/n);
66 }
67 
68 void solve(){
69     init();
70     int s,t,mat[55][55];
71     scanf("%d%d",&n,&m);
72     s = 0;t = n * m + n + 1;
73     for(int i=1;i<=n;i++)
74         for(int j=1;j<=m;j++)
75         scanf("%d",&mat[i][j]);
76     for(int i = 1; i <= n; i ++)
77     {
78         addedge(s,i,1,0);
79         for(int j = 1; j <= n; j ++)
80         {
81             for(int k = 1; k <= m; k ++)
82             {
83                 addedge(i,n+(k-1)*n+j,1,j*mat[i][k]);
84             }
85         }
86     }
87     for(int i=n+1;i<=n*m+n;i++)
88         addedge(i,t,1,0);
89     MCMF(s,t);
90 }
91 int main()
92 {
93    //freopen("a.txt","r",stdin);
94     int t;
95     scanf("%d",&t);
96     while(t--) solve();
97     return 0;
98 }

 

posted @ 2015-08-04 12:11  NowAndForever  阅读(229)  评论(0编辑  收藏  举报