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 }

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

时间: 2024-10-12 03:04:36

poj - 3686 The Windy's (KM算法)的相关文章

[ACM] POJ 3686 The Windy&#39;s (二分图最小权匹配,KM算法,特殊建图)

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4158   Accepted: 1777 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receivesN orders for toys. The man

poj 3686 The Windy&#39;s 二分图最小权和匹配KM

题意: 给n个玩具和m家工厂,每个玩具只能在一家工厂加工,给出每个玩具在每家工厂需要的加工时间,求这n个玩具完成时间平均值的最小值. 分析: 求最小和容易联系到二分图的最小权和匹配,这题的问题是n与m的大小关系是不确定的,也是就是说可能会有多个玩具到同一家工厂里加工的情况,这似乎与匹配的定义相矛盾.但仔细一想,如果多个玩具在同一工厂加工,他们的完成时间肯定是不一样的,所以讲w[i][j]=z 拆成w[i][0*m+j]=z,w[i][1*m+j]=2*z,w[i][2*m+j]=3*z.....

POJ 3686 The Windy&#39;s【最小权匹配(神建图啊)】

大意:有n个任务m个机器,告诉你n*m的矩阵表示每个任务在每个机器上完成需要的时间 问所有任务完成的总时间最少?(比如第一个任务在第一分钟完成第二个任务在第二分钟完成   则总时间为1 + 2 = 3 分析: 该题自己做的时候没有思路 后来在网上搜题解,感觉建图真是太厉害了 假设最优情况下,个个任务需要的时间分别为a1, a2, a3, ……,an 那么总时间t = n * a1 + (n - 1) * a2 + ……+ 2 * an - 1 + an 也就是说只需要考虑系数就可以了 我们先假设

POJ 3686 The Windy&#39;s 最小权值匹配

点击打开链接 The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3788   Accepted: 1630 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys.

POJ 3686.The Windy&#39;s 最小费用最大流

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5477   Accepted: 2285 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The ma

POJ 3686 The Windy&#39;s(思维+费用流好题)

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5362   Accepted: 2249 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The ma

POJ 3686 The Windy&#39;s

拆点+最小费用最大流: 将工厂拆点,表示再第j个工厂倒数第k个生产则第i个玩具到(j,k)工厂的费用为 k*t[i][j] The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4066   Accepted: 1746 Description The Windy's is a world famous toy factory that owns M top-class workshop to make

POJ-3686 The Windy&#39;s KM算法 拆点题

参考:https://blog.csdn.net/sr_19930829/article/details/40680053 题意: 有n个订单,m个工厂,第i个订单在第j个工厂生产的时间为t[i][j],同一个工厂可以生产多个订单,但一次只能生产一个订单,也就是说如果先生产a订单,那么b订单要等到a生产完以后再生产,问n个订单用这m个工厂全部生产完需要最少的时间是多少. 思路: 这道题好像用费用流也可以,建图思路好像也是一样的.每个订单耗费时间和在工厂中的等待顺序是有关系的.显然,如果一个工厂有

POJ 2195 二分图最小权匹配KM算法

本来是打算昨天晚上写的, 昨天网速渣的连CSDN都进不去,没办法 只能现在来写了 先写写对KM算法的理解,KM算法是对每个点设置一个顶标,只有当边长等于两边点的顶标之和的时候才进行增广,这样就能保证得到的一定是最大权匹配. 如果找不到匹配的时候就对交替路中X集合的顶标减少一个d Y集合的顶标增加一个d. 这样两个点都在交替路中的时候x[i]+y[i]的和不边 X在 Y不在的时候x[i]+y[i]减少,可能就会为图增加一对匹配. X不在Y在的时候x[i]+y[i]增加, 原来不在现在依然不在其中.