POJ 3686 —— 最小費用流||最小費用匹配&KM

The Windy's
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 3520   Accepted: 1509

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 manager knows that every order will take different amount of hours in different workshops. More precisely, the i-th order will take Zij hours if the toys are making in the j-th workshop. Moreover, each order's work must be wholly completed in the same workshop. And a workshop can not switch to another order until it has finished the previous one. The switch does not cost any time.

The manager wants to minimize the average of the finishing time of the N orders. Can you help him?

Input

The first line of input is the number of test case. The first line of each test case contains two integers, N and M (1 ≤ N,M ≤ 50).
The next N lines each contain M integers, describing the matrix Zij (1 ≤ Zij ≤ 100,000) There is a blank line before each test case.

Output

For each test case output the answer on a single line. The result should be rounded to six decimal places.

Sample Input

3

3 4
100 100 100 1
99 99 99 1
98 98 98 1

3 4
1 100 100 100
99 1 99 99
98 98 1 98

3 4
1 100 100 100
1 99 99 99
98 1 98 98

Sample Output

2.000000
1.000000
1.333333

Source

題意是有n個玩具,交給m個工廠,j號工廠加工i號玩具需要Z[i][j]時間,求加工完所有玩具的平均時間

思路:這題有兩種解法比較方便,首先是最小費用匹配KM算法,據說極快;第二種是最小費用流,時間860MS,比較慢。我用的是第二種。

我們把多個工廠加工一個玩具轉化爲一個多個只能加工一種玩具的多個工廠,他們分別花費1- N倍的時間。然後就是一個經典的指派問題,最小費用流可解。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
///#define Online_Judge
#define outstars cout << "***********************" << endl;
#define clr(a,b) memset(a,b,sizeof(a))
#define lson l , mid  , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define mk make_pair
#define FOR(i , x , n) for(int i = (x) ; i < (n) ; i++)
#define FORR(i , x , n) for(int i = (x) ; i <= (n) ; i++)
#define REP(i , x , n) for(int i = (x) ; i > (n) ; i--)
#define REPP(i ,x , n) for(int i = (x) ; i >= (n) ; i--)
const int MAXN = 50 + 5;
const int sigma_size = 26;
const long long LLMAX = 0x7fffffffffffffffLL;
const long long LLMIN = 0x8000000000000000LL;
const int INF = 0x7fffffff;
const int IMIN = 0x80000000;
#define eps 1e-8
const int MOD = (int)1e9 + 7;
typedef long long LL;
const double PI = acos(-1.0);
typedef pair<int , int> pi;
const int mod = 1000000000;
#define Bug(s) cout << "s = " << s << endl;
///#pragma comment(linker, "/STACK:102400000,102400000")
int t , n , m ;
int Z[MAXN][MAXN];
struct edge{int to , cap , cost ,rev;};
vector <edge> G[MAXN * MAXN];
int V;
int h[MAXN * MAXN];
int dist[MAXN * MAXN];
int prevv[MAXN  * MAXN] , preve[MAXN*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;
    fill(h , h + V , 0);
    while(f > 0)
    {
        priority_queue<pi , vector<pi> , greater<pi> >que;
        fill(dist , dist + V , INF);
        dist[s] = 0;
        que.push(pi(0 , s));
        while(!que.empty())
        {
            pi p = que.top();que.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;
                    que.push(pi(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;
}
void solve()
{
    ///0 -- n - 1:玩具
    ///n -- 2* n - 1:0號工廠
    ///2 * n -- 3 * n - 1: 1號工廠
    ///...
    ///m * n -- (m + 1) * n - 1:m-1號工廠
    int s = n * m + n , t= s + 1;
    V = t + 1;
    for(int i = 0 ; i < n ; i++)
    {
        add_edge(s , i , 1 , 0);
    }
    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 , (k + 1) * Z[i][j]);
            }
        }
    }
    printf("%.6f\n" , (double)min_cost_flow(s , t , n) / n);
}

int main()
{
    cin >> t;
    while(t--)
    {
        clr(preve , 0);
        clr(prevv , 0);
        clr(G , 0);
        scanf("%d%d" , &n , &m);
        for(int i = 0 ; i < n ; i++)
        {
            for(int j = 0 ; j < m ; j++)
            {
                scanf("%d",&Z[i][j]);
            }
        }
        solve();
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章