题意:

N个工件要在M个工厂加工,一个工件必须在一个工厂做完,工厂一次只能处理一个工件。给定每个工件在每个工厂加工所需时间,求出每个工件加工结束的最小时间平均值。

分析:

工厂一次只能处理一个工件,那么其他要在这个工厂处理的工件就要排队等待,如果有a个工件要在该厂处理,花的时间分别为n1,n1+n2,...,n1+n2+n3..na,该工厂花的总时间就为a∗n1+(a−1)∗n2+...+1∗na,这样将每个工厂拆为N个点,表示每个工件的完成花费了1..N倍的时间(别的工件等待的时间+处理该工件的时间),便可以转化为二分图最大权匹配问题。

代码:

最小费用最大流解法:

#include<cstdio>
#include<vector>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define se second
#define fi first
typedef pair<int, int>pii;//first 顶点距离,secon顶点编号
struct edge{int to, cap, cost, rev;};
const int maxn = 30005, maxm = 500, INF =0x3f3f3f3f;
int V, s, t;
vector<edge>G[maxn];
int dist[maxn], prevv[maxn], preve[maxn], h[maxn];//h记录顶点的势
int z[maxm][maxm];
void add_edge(int from, int to, int cap, int cost)
{
G[from].push_back((edge){to, cap, cost, G[to].size()});
G[to].push_back((edge){from, 0, -cost, G[from].size() - 1});
}
int min_cost_flow(int s, int f)
{
int res = 0;
fill(h, h + V + 1, 0);
while(f > 0){
priority_queue<pii, vector<pii>, greater<pii> >que;
fill(dist, dist + V + 1, INF);
dist[s] = 0;
que.push(pii(0, s));
while(!que.empty()){
pii p = que.top();que.pop();
int v = p.se;
if(dist[v] < p.fi) continue;
for(int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
if(e.cap>0&&dist[e.to]>dist[v] + e.cost + h[v] - h[e.to]){
dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
prevv[e.to] = v; preve[e.to] = i;
que.push(pii(dist[e.to], e.to));
}
}
}
if(dist[t] == INF) return -1;
for(int i = 1; i <= V; i++) h[i] +=dist[i];
int d = f;
for(int v = t; v != s; v = prevv[v]){
d = min(d, G[prevv[v]][preve[v]].cap);
}
f -= d;
res += d * h[t];
for(int v = t; v!= s; v = prevv[v]){
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
int main (void)
{
int c;scanf("%d",&c);
while(c--){
memset(G, 0, sizeof(G));
int N, M;scanf("%d%d",&N,&M);
s = N * (M + 1), t = s + 1;
for(int i = 0; i < N; i++){
add_edge(s, i, 1, 0);
for(int j = 0; j < M; j++){
scanf("%d",&z[i][j]);
}
}
for(int j = 0; j < M; j++){
for(int k = 0; k < N; k++){
add_edge(N + j * N + k, t, 1, 0);
for(int i = 0; i < N; i++)
add_edge(i, N + j * N + k, 1, z[i][j] * (k + 1));
}
}
V = t + 1;
printf("%.6f\n", (double)min_cost_flow(s, N)/N);
} }

KM算法:

很清晰的KM讲解1

很清晰的讲解2

非常生动的匈牙利算法讲解

求解二分图最大权匹配,KM时间复杂度O(n3),比最小费用最大流解法快多了!

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int N, M, nm, nn;
const int maxn = 2555, INF = 0x3f3f3f3f;
int usex[55], usey[maxn], match[maxn], lx[55], ly[maxn], slack[maxn];
int z[55][maxn];
bool Find(int x)
{
usex[x] = 1;
for(int i = 0; i < nm; i++){
if(usey[i]) continue;
int s = lx[x] + ly[i] - z[x][i];
if(s == 0){
usey[i] = 1;
if(match[i] == -1|| Find(match[i] )){
match[i] = x;
return true;
}
}else if(slack[i] > s){
slack[i] = s;
}
}
return false;
}
int KM()
{
memset(ly, 0, sizeof(ly));
memset(match, -1, sizeof(match));
for(int i = 0; i <nn; i++){
lx[i] = - INF;
for(int j = 0; j < nm; j++){
if(lx[i] < z[i][j])
lx[i] = z[i][j];
}
}
for(int a = 0; a < nn; a++){
memset(slack, 0x3f, sizeof(slack));
for(;;){
memset(usex, 0,sizeof(usex));
memset(usey, 0, sizeof(usey));
if(Find(a)) break;
int d = INF;
for(int i = 0; i < nm; i++){
if(!usey[i] && d > slack[i]){
d = slack[i];
}
}
for(int i = 0; i < nn; i++){
if(usex[i]) lx[i] -= d;
}
for(int i = 0; i < nm; i++){
if(usey[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int sum = 0;
for(int i = 0; i < nm; i++){
if(match[i] > -1){
sum += z[match[i]][i];
}
}
return -sum;
}
int main (void)
{
int c;scanf("%d",&c);
while(c--){
scanf("%d%d",&N,&M);
int t;
nn = N, nm = N * M;
for(int i = 0; i < N; i++){
for(int j = 0; j < M; j++){
scanf("%d",&t);
for(int k = 0; k < N; k++)
z[i][j * N + k] = - t * (k + 1);
}
}
printf("%.6f\n", (double)KM()/N);
}
}

垃圾WA,垃圾垃圾!


关于KM的拓展:

  • 如果是求最小权,则可以把lx[i[初始化为min(g[i][j]),并在find函数中进行相应改变,也可以简单的将所有边取负数,计算最大权,然后结果再取负数即可。
  • 权的最大积的话,把边取对数,然后计算最大权就好啦~最后记得答案要取e的幂~

POJ 3686_The Windy's的更多相关文章

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

    The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4158   Accepted: 1777 Descr ...

  2. POJ 3686 The Windy's(思维+费用流好题)

    The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5362   Accepted: 2249 Descr ...

  3. poj 3686 The Windy's

    http://poj.org/problem?id=3686 #include <cstdio> #include <cstring> #include <algorit ...

  4. POJ 3686 The Windy's (费用流)

    [题目链接] http://poj.org/problem?id=3686 [题目大意] 每个工厂对于每种玩具的加工时间都是不同的, 并且在加工完一种玩具之后才能加工另一种,现在求加工完每种玩具的平均 ...

  5. POJ 3686:The Windy's(最小费用最大流)***

    http://poj.org/problem?id=3686 题意:给出n个玩具和m个工厂,每个工厂加工每个玩具有一个时间,问要加工完这n个玩具最少需要等待的平均时间.例如加工1号玩具时间为t1,加工 ...

  6. POJ 3686 The Windy's 最小费用最大流

    每个工厂拆成N个工厂,费用分别为1~N倍原费用. //#pragma comment(linker, "/STACK:1024000000,1024000000") #includ ...

  7. POJ 3686 The Windy's (最小费用流或最佳完全匹配)

    题意:有n个订单m个车间,每个车间均可以单独完成任何一个订单.每个车间完成不同订单的时间是不同的.不会出现两个车间完成同一个订单的情况.给出每个订单在某个车间完成所用的时间.问订单完成的平均时间是多少 ...

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

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

  9. Poj(3686),最小权匹配,多重匹配,KM

    题目链接 The Windy's | Time Limit: 5000MS | Memory Limit: 65536K | | Total Submissions: 4939 | Accepted: ...

随机推荐

  1. 自学 iOS - 三十天三十个 Swift 项目 第二天

    继续做仿造着别人的第二个 1.首先下载 一些字体 网上搜索 "造字工房" 2.把下载的相应字体文件放到工程之中,就Ok了 不多说 效果如下 可以下面这个方法 检索项目里面所有的字体 ...

  2. laravel学习:容器绑定与解析

    1.在服务容器中注册类(bind) $this->app->bind('sender','MailSender');//$this->app成为服务容器.   2.从服务容器生成类( ...

  3. js 类似于移动端购物车删除,左移动删除

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Seating Arrangement

    1997: Seating Arrangement Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 543     Solved:  ...

  5. autorun - 自动装载/卸载CDROMs并在装载后执行/path/to/cdrom/autorun

    总览 autorun [-lmqv?V] [-a EXEC] [-c CDPLAYER] [-e STRING] [-i MILLISEC] [-n STRING] [-t STRING] [--au ...

  6. zay大爷的神仙题目 D1T3-膜你抄

    依旧是外链 锦鲤抄 [题目背景] 你在尘世中辗转了千百年 却只让我看你最后一眼 火光描摹容颜燃尽了时间 别留我一人,孑然一身 凋零在梦境里面. ——银临&云の泣<锦鲤抄> [问题描 ...

  7. P2P实现的原理

    为了项目的后期IM应用,最近在研究libjingle,中间看了也收集了很多资料,感慨网上很多资料要么太过于纠结协议(如STUN.ICE等)实现细节,要么中间有很多纰漏.最后去伪存真,归纳总结了一下,希 ...

  8. 浏览器通知js授权

    // 获得权限 Notification.requestPermission(); // 点击按钮 document.querySelector('#button').addEventListener ...

  9. jsMap地图网点

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <meta name=& ...

  10. 「 Luogu P1122 」 最大子树和

    # 题目大意 真讨厌题面写的老长老长的. 这个题的意思就是给定一棵无根树,每个节点都有一个美丽值(可能是负数),可以删掉一些边来删除某些点,现在要求你求出可以删掉任意条边的情况下,这个树上的剩余节点的 ...