POJ 3686 *最小费用流-转化成普通指派问题)

题意】

有N个订单和M个机器,给出第i个订单在第j个机器完成的时间Mij,每台机器同一时刻只能处理一个订单,机器必须完整地完成一个订单后才能接着完成下一个订单。问N个订单完成时间的平均值最少为多少。

分析 :

最小费用最大流
如果每个工厂只能完成一个订单的话,那就是指派问题了。跑一遍最小费用流即可。但是题目每个工厂可能完成多个。
所以需要将其拆点使得每个工厂只能完成一个订单,进而转换成指派问题。对一个工厂来说,如果每个订单都在这个
工厂完成的话,那么时间为T=t1 + (t1+t2) + (t1+t2+t3) +... = n*t1 + (n-1)*t2 + (n-2)*t3 + ...就可将其看成
是n个只能完成一个订单的工厂只不过它们需要乘于花费的1到N倍。

 

#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
 
using namespace std;
const int maxn = 3000;
const int INF = 0x3f3f3f3f;
 
typedef pair<int,int> P;
struct Edge
{
    int to, cap, cost, rev;
    Edge(int to_, int cap_, int cost_, int rev_):to(to_),cap(cap_),cost(cost_),rev(rev_){}
};
 
vector<Edge> G[maxn];
int V, n, m, relation[55][55];
int h[maxn], dist[maxn], prevv[maxn], preve[maxn];
 
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 t, int f)
{
    int res = 0;
    memset(h, 0, sizeof(h));
    while(f > 0) {
        priority_queue<P, vector<P>, greater<P> > pq;
        fill(dist, dist + V, INF);
        dist[s] = 0;
        pq.push(P(0, s));
        while(!pq.empty()) {
            P p = pq.top(); pq.pop();
            int v = p.second;
            if(dist[v] < p.first)   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;
                    pq.push(P(dist[e.to], e.to));
                }
            }
        }
        if(dist[t] == INF)  return -1;
 
        for(int v = 0; v < V; v++)  h[v] += dist[v];
 
        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()
{
    //freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);    getchar();
    while(T--) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < maxn; i++)   G[i].clear();
 
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                scanf("%d", &relation[i][j]);
            }
        }
 
        int s = n + n * m, t = s + 1;
        for(int j = 0; j < m; j++) {//工厂
            for(int k = 0; k < n; k++) {//将工厂拆成n个点
                add_edge(n + j * n + k, t, 1, 0);
                for(int i = 0; i < n; i++) {
                    add_edge(i, n + j * n + k, 1, (k + 1) * relation[i][j]);
                }
            }
        }
        for(int i = 0; i < n; i++)  add_edge(s, i, 1, 0);
        V = t + 1;
        printf("%.6f\n", (double)min_cost_flow(s, t, n) / n);
    }
    return 0;
}
View Code

 

posted @ 2018-07-18 10:00  shuai_hui  阅读(198)  评论(0编辑  收藏  举报