题意:

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. AJPFX总结泛型概念和使用

    泛型泛型(generic)概述和基本使用                泛型把明确数据类型的操作放到创建对象或者调用方法的时候再明确.                                J ...

  2. Linux之测试服务器和端口连通

    目录 wget工具 telnet工具 ssh工具 wget工具: 该工具是网络自动下载工具,如果linux或centos中不存在,需要先安装,支持http.https.ftp协议,wget名称的由来是 ...

  3. 2019PAT春季考试第4题 7-4 Structure of a Binary Tree (30 分)

    题外话:考试的时候花了一个小时做了27分,由于Siblings这个单词不知道意思,所以剩下的3分就没去纠结了,后来发现单词是兄弟的意思,气哭~~ 这道题的麻烦之处在于如何从一个字符串中去找数字.先首先 ...

  4. iOS---小经验分享

    1.字符串在block中得赋值 定义一个全局变量,<字符串>当这个字符串用copy修饰的时候,然后再在block中赋值,当在block块之外访问时,不能得到字符创的值.此时字符串应该设置为 ...

  5. taskctl的后台字符界面登录不了解决办法

    今天在使用taskctl的designer时,十多分钟挂了2次,每次挂了之后就签不出来了,只能等半小时,然后在taskctl的QQ群里咨询了,给的解决方案是 http://www.taskctl.co ...

  6. Vue.js语法糖整理

    el:element 需要获取的元素,一定是HTML中的根容器元素 data:用于数据的存储 methods:用于存储各种方法 数据绑定字面量只加载一次{{* msg}} data里面可以进行简单的运 ...

  7. Linux内核中TCP SACK机制远程DoS预警通告

    漏洞描述 2019年6月18日,RedHat官网发布报告:安全研究人员在Linux内核处理TCP SACK数据包模块中发现了三个漏洞,CVE编号为CVE-2019-11477.CVE-2019-114 ...

  8. jQuery动态移除和绑定事件

    function bindEvent() { //移除绑定事件 $('.btnsp').unbind('click'); //绑定事件 $('.btnsp').bind('click', functi ...

  9. mysql中删除已有字段的唯一性约束?

    username varchar() NOT NULL unique 如何把unique约束删除? 解决方法:在你建好的表...右击 ——索引/索引类型——把username唯一键去掉

  10. 网络共享服务器 samba

    之前给自己centos 服务器配置了一下samba网络共享,主要是在windwos上编程,然后方便代码同步到linux上进行编译,现在大概记录一下过程,免得下次又忘记了 首先获取root权限 :su ...