POJ3686 The Windy's

The Windy's
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 5412 Accepted: 2268

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

————————————————————————————————

题意:有n个任务和m个车间,每个任务在不同的车间内完成花费的时间不同,且每个车间只能完成一个任务后才能接下一个任务,求完成所有任务的最小平均时间。


思路:最小费用最大流,拆点将m个车间都拆成n个,,表示第i个任务在第j个车间的第k个时间段完成。建图时,把每个任务看做一个源点,将其连向每个时间段的点,权值为经过累积计算后的花费,容量为1,矩阵中的每个点连向超级汇点,容量为1,花费为0,表示这个这件在这个时候只能使用一次,同时加入超级源点,将其连向每个任务,容量为1,花费为0。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;
#define MAXN 100100
#define MAXM 1000100

int vis[MAXN],d[MAXN],pre[MAXN],aa[MAXN];

struct Edge
{
    int u, v, c, cost, next;
} edge[MAXM];
int s[MAXN], cnt;

void init()
{
    cnt = 0;
    memset(s, -1, sizeof(s));
}

void add(int u, int v, int c, int cost)
{
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].cost = cost;
    edge[cnt].c = c;
    edge[cnt].next = s[u];
    s[u] = cnt++;
    edge[cnt].u = v;
    edge[cnt].v = u;
    edge[cnt].cost = -cost;
    edge[cnt].c = 0;
    edge[cnt].next = s[v];
    s[v] = cnt++;
}

bool spfa(int ss, int ee,int &flow,int &cost)
{
    queue<int> q;
    memset(d, INF, sizeof d);
    memset(vis, 0, sizeof vis);
    d[ss] = 0, vis[ss] = 1, pre[ss] = 0, aa[ss] = INF;
    q.push(ss);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = s[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].v;
            if (edge[i].c>0&& d[v]>d[u] + edge[i].cost)
            {
                d[v] = d[u] + edge[i].cost;
                pre[v] = i;
                aa[v] = min(aa[u], edge[i].c);
                if (!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if (d[ee] == INF) return 0;
    flow += aa[ee];
    cost += d[ee]*aa[ee];
    int u = ee;
    while (u != ss)
    {
        edge[pre[u]].c -= aa[ee];
        edge[pre[u] ^ 1].c += aa[ee];
        u = edge[pre[u]].u;
    }
    return 1;
}

int MCMF(int ss, int ee)
{
    int cost = 0, flow=0;
    while (spfa(ss, ee, flow, cost));

    return cost;
}



int main()
{
    int T,n,m,u,v,c,x;
    for(scanf("%d",&T); T--;)
    {
        init();
        scanf("%d%d",&m,&n);
        for(int i=1; i<=m; i++)
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&x);
                for(int k=0; k<m; k++)
                {
                    add(i,m+j+k*n,1,x*(k+1));
                }
            }
            for(int i=1;i<=m;i++)
                add(0,i,1,0);
            for(int j=1;j<=n;j++)
                for(int k=0; k<m; k++)
                {
                    add(m+j+k*n,100000,1,0);
                }
            printf("%.6f\n",MCMF(0,100000)*1.0/m);



    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值