POJ 3686 The Windy's(思维+费用流好题)

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

转载于:https://www.cnblogs.com/Blackops/p/7103040.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值