POJ3686 The Windy's

本文探讨了如何通过优化玩具工厂的生产流程,特别是通过合理分配订单到不同工作车间来最小化订单完成时间的平均值。通过构建数学模型和使用费用流算法,实现了在不同车间间高效调度任务,从而有效降低整体生产周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Windy's

Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 3933 Accepted: 1688
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个任务,给出了每个任务在每个机器上完成的时间,求完成所有任务的平均时间最小。

完成任务的总时间就等于每个任务完成所需要的时间加上等待的时间,这题建图很好,要将任务拆点,建一个源点,从每个任务连一条边到任务,流量1,费用0,再将任务拆点,从任务i连一条边到n+(j-1)*n+k,表示任务i在机器j上被处理,k表示处理的次序,流量为1,费用k*mp[i][j],因为有可能有任务在这个机器上被处理,这个就表示等待的时间,最后再从被拆点的n的右边连一条边到汇点就行,然后跑一遍费用流就是答案了,这题点的个数n+n*m+2(n*m表示每个机器处理同一个任务的次序),边的个数n*m*n+n+n*m(n*m*n是任务i和n+(j-1)*n+k的边的个数),因为有反向边,所以还要*2.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=3010;
const int MAXE=(2500*50+2500+50)*2;
const int INF=1<<30;
int head[MAXN],size;
struct EDGE
{
    int v,next;
    int cap;
    int cost;
}edge[MAXE];
void init()
{
    memset(head,-1,sizeof(head));
    size=0;
}
void add_edge(int u,int v,int cap,int cost)
{
    edge[size].v=v;
    edge[size].cap=cap;
    edge[size].cost=cost;
    edge[size].next=head[u];
    head[u]=size++;
    edge[size].v=u;
    edge[size].cap=0;
    edge[size].cost=-cost;
    edge[size].next=head[v];
    head[v]=size++;
}
int dist[MAXN],pre[MAXN],pe[MAXN];
bool vis[MAXN];
bool spfa(int s,int t)
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i=0;i<=t+1;i++)
        dist[i]=INF;
    dist[s]=0;
    vis[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost)
            {
                dist[v]=dist[u]+edge[i].cost;
                pe[v]=i;
                pre[v]=u;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t]==-1)
        return 0;
    return 1;
}
int max_flow;
int MCMF(int s,int t)
{
    int min_cost=0;
    max_flow=0;
    while(spfa(s,t))
    {
        int aug=INF;
        for(int v=t;v!=s;v=pre[v])
        {
            aug=min(aug,edge[pe[v]].cap);
        }
        max_flow+=aug;
        min_cost+=aug*dist[t];
        for(int v=t;v!=s;v=pre[v])
        {
            edge[pe[v]].cap-=aug;
            edge[pe[v]^1].cap+=aug;
        }
    }
    return min_cost;
}
int mp[55][55];
int main()
{
    int t,n,m,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&m);
        int s=0,t=n+n*m+1;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                scanf("%d",&mp[i][j]);
            }
        }
        for(i=1;i<=n;i++)
            add_edge(s,i,1,0);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                for(k=1;k<=n;k++)
                {
                    add_edge(i,n+(j-1)*n+k,1,mp[i][j]*k);   //i任务在机器j上第几个被处理
                }
            }
        }
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=n;j++)
            {
                add_edge(n+(i-1)*n+j,t,1,0);
            }
        }
        int ans=MCMF(s,t);
        printf("%.6f\n",ans*1.0/n);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值