1. 程式人生 > >POJ 3686 The Windy's(思維+費用流好題)

POJ 3686 The Windy's(思維+費用流好題)

rst ase numeric new -s 第一次 -c ber 當前

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 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

題目連接:POJ 3686

刷白書的網絡流問題看到的,跟某一道導彈發射的問題很像,但是這題不同工廠對不同的物品都有不同的加工時間,按加工次序拆點是很容易想到, 但這樣一想有一個問題,比如我把物品連到工場2的第二次加工時間點,那我這條邊流量是1,費用是多少根本不知道,因為我不知道工廠2第一次加工的那條邊費用是多少,即不知道當前物品加工時等待了多久,因此需要換一種思路。

比如有三個物品a,b,c都在同一個工廠加工,那麽時間可以這麽寫:ta+ta+tb+ta+tb+tc=3ta+2tb+1tc,顯然最先加工的是a,其次是b,最後是c,可以發現物品前面的系數的最大值就是在工廠加工的總物品數,那麽這題實際上就是一個系數分配問題,那麽建圖就好辦了, 費用就是加工次序*加工時間,由於流量是1,確實解決了同一時間只能加工一個物品的問題,但可能又會想,那我的某一個物品萬一在工廠1的第k次序加工,但是實際上工廠1前k-1次機會都沒有用過,這豈不是非常浪費嗎?實際上由於用的是SPFA最短路增廣,求解過程就是求出了總時間最優的情況,不會出現前面空著的加工次序問題,如果有空著的加工次序,那麽SPFA一定會找到並把這條邊松弛算進網絡流中

代碼:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <numeric>
#include <cstring>
#include <bitset>
#include <string>
#include <deque>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 55;
const int MAXV = N + N * N;
const int MAXE = N + N * N + N * N * N;
struct edge
{
    int to, nxt, cap, cost;
    edge() {}
    edge(int _to, int _nxt, int _cap, int _cost): to(_to), nxt(_nxt), cap(_cap), cost(_cost) {}
};
edge E[MAXE << 1];
int head[MAXV], tot;
int vis[MAXV], pre[MAXV], path[MAXV], d[MAXV];
int Z[N][N];
int mc, mf;

void init()
{
    CLR(head, -1);
    tot = 0;
    mc = mf = 0;
}
inline void add(int s, int t, int cap, int cost)
{
    E[tot] = edge(t, head[s], cap, cost);
    head[s] = tot++;
    E[tot] = edge(s, head[t], 0, -cost);
    head[t] = tot++;
}
int spfa(int s, int t)
{
    queue<int>Q;
    Q.push(s);
    CLR(d, INF);
    CLR(vis, 0);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        for (int i = head[u]; ~i; i = E[i].nxt)
        {
            int v = E[i].to;
            if (d[v] > d[u] + E[i].cost && E[i].cap > 0)
            {
                d[v] = d[u] + E[i].cost;
                pre[v] = u;
                path[v] = i;
                if (!vis[v])
                {
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
    return d[t] != INF;
}
void MCMF(int s, int t)
{
    int i;
    while (spfa(s, t))
    {
        int Min = INF;
        for (i = t; i != s; i = pre[i])
            Min = min(Min, E[path[i]].cap);
        for (i = t; i != s; i = pre[i])
        {
            E[path[i]].cap -= Min;
            E[path[i] ^ 1].cap += Min;
        }
        mf += Min;
        mc += Min * d[t];
    }
}
int main(void)
{
    int tcase, n, m, i, j, k;
    scanf("%d", &tcase);
    while (tcase--)
    {
        init();
        scanf("%d%d", &n, &m);
        for (i = 1; i <= n; ++i)
            for (j = 1; j <= m; ++j)
                scanf("%d", &Z[i][j]);
        int S = 0, T = n + n * m + 1;
        for (i = 1; i <= n; ++i) //n源點到需加工物品
            add(S, i, 1, 0);
        for (i = n + 1; i <= n + n * m; ++i) //n*m加工時間點到匯點
            add(i, T, 1, 0);
        for (i = 1; i <= n; ++i)
        {
            for (j = 1; j <= m; ++j)
            {
                for (k = 1; k <= n; ++k)//遍歷不同時間點
                {
                    int id = j * n + k;
                    add(i, id, 1, k * Z[i][j]); //n*m*n
                }
            }
        }
        MCMF(S, T);
        printf("%.6f\n", mc * 1.0 / n);
    }
    return 0;
}

POJ 3686 The Windy's(思維+費用流好題)