poj 3686

N 个工件要在 M 个机器上加工,有一个 NM 的矩阵描述其加工时间。
同一时间内每个机器只能加工一个工件,问加工完所有工件后,使得平均加工时间最小(等待的时间+加工的时间)

假设某个机器处理了 k 个玩具,时间分别为 a1,a2..,ak

那么该机器耗费的时间为 a1+a1+a2+a1+a2+a3.......a1+a2+...ak

a1k+a2(k1)+a3(k2)....+ak
ai 玩具在某个机器上倒数第 k 个处理,所耗费全局的时间为 aik

对每个机器,最多可以处理 n 个玩具,拆成 n 个点, 1 ~n 分别代表某个玩具在这个机器上倒数第几个被加工的,对于每个玩具 i ,机器 j 中拆的每个点 k ,连接一条 w[i][j]k 权值的边


转自http://www.cnblogs.com/Missa/archive/2012/09/29/2708441.html


KM模板


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
const int MAXN = 55 , MAXM = 55 , MAXY = 2505, INF  = 1<<30;

int n, m , nx, ny;
int mat[MAXN][MAXM] = {0};
int w[MAXN][MAXY] = {0};
int lx[MAXN] = {0}, ly[MAXY] = {0};
//n toys  m machines
int link[MAXY] = {0},slack[MAXY] = {0};
bool visx[MAXN] = {0},visy[MAXY] = {0};

void init()
{
    scanf("%d%d",&n,&m);

    for(int i = 1 ; i <= n; i++)
      for(int j = 1 ; j <= m ;j++)
        scanf("%d",&mat[i][j]);
}
void build()
{
    for(int i = 1 ; i <= n ; i++)
      for(int j = 1 ; j <= m ; j++)
        for(int k = 1 ; k <= n ; k++)
        {
          w[i][(j-1)*n + k] = -mat[i][j]*k;
        }
    nx = n , ny = n*m;    
}
bool find(int x)
{
    visx[x] = true;

    for(int y = 1 ; y <= ny ; y++)
    {
        if(visy[y] == true)continue;

        int tmp = lx[x] + ly[y] - w[x][y];

        if(!tmp)
        {
            visy[y] = true;

            if(!link[y] || find(link[y])==true)
               {link[y] = x;return true;}
        }
        slack[y] = std::min(slack[y],tmp);
    }
    return false;
}
int KM()
{
    int ret = 0;

    memset(link,0,sizeof(link));
    memset(ly,0,sizeof(ly));
    for(int i = 1 ; i <= nx; i++)
    {
     lx[i] = -INF;
     for(int j = 1 ; j <= ny ; j++)
       lx[i] = std::max(lx[i],w[i][j]);  
    }

    for(int x = 1 ; x <= nx; x++)
    {
      for(int j = 1 ; j <= ny ; j++)
        slack[j] = INF; 

      while(1)
      {
          memset(visx,false,sizeof(visx));
          memset(visy,false,sizeof(visy));

          if(find(x)==true)break;

          int d = INF;

          for(int j = 1 ; j <= ny ; j++)
            if(!visy[j])d = std::min(d,slack[j]);

          for(int i = 1 ; i <= nx ; i++)
            if(visx[i]) lx[i]-=d;
          for(int j = 1 ; j <= ny ; j++)
            if(!visy[j])slack[j]-=d;
            else        ly[j]+=d;  
      }
    }

    for(int j = 1; j <= ny ; j++)
      if(link[j])ret+=w[link[j]][j];

    return -ret;  
}
int main()
{
    int T;
#ifndef ONLINE_JUDGE    
    freopen("poj3686.in","r",stdin);
    freopen("poj3686.out","w",stdout);
#endif
    scanf("%d",&T);    
    while(T--)
    {
        init(); build();
        int cost = KM();
        printf("%.6lf\n",(double)cost/n);
    }
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif 
    return 0;       
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值