题意:有M个工作间,N个玩具订单,求最小的平均完成时间
思路:对M个工作间分成N个点,j的第p个点表示倒数第p次加工,若要在一个工作间上完成k个订单则需要假设我们按顺序在J机器上工件I1,I2,I3..IK个工件,则总共需要花费I1*K+I2*(K- 1)+I3*(K-3)++IK, 所以我们对于X中每个点I,Y中每个点(J,P),连接一条A[I,J]*P权值的边.
代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define INF 1e15
#define maxn 60
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
int sx[maxn],sy[maxn*maxn];
int lx[maxn],ly[maxn*maxn],mat[maxn*maxn];
int martix[maxn][maxn],ca,m,n;
int w[maxn][maxn*maxn];
void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int p=1;p<=n;p++)
w[i][(j-1)*n+p]=-martix[i][j]*p;
}
bool find(int x)
{
sx[x]=1;
for(int i=1;i<=n*m;i++)
{
if(!sy[i]&&lx[x]+ly[i]==w[x][i])
{
sy[i]=1;
if(mat[i]==-1||find(mat[i]))
{
mat[i]=x;
return 1;
}
}
}
return 0;
}
int KM()
{
for(int i=1;i<=n*m;i++) ly[i]=0;
for(int i=1;i<=n;i++)
{
lx[i]=-INF;
for(int j=1;j<=n*m;j++)
lx[i]=max(lx[i],w[i][j]);
}
clr(mat,-1);
for(int i=1;i<=n;i++)
while(1)
{
clr(sx,0);
clr(sy,0);
if(find(i)) break;
int d=INF;
for(int k=1;k<=n;k++)
if(sx[k])
for(int j=1;j<=n*m;j++)
if(!sy[j])
d=min(d,lx[k]+ly[j]-w[k][j]);
for(int k=1;k<=n;k++) if(sx[k]) lx[k]-=d;
for(int k=1;k<=m*n;k++) if(sy[k]) ly[k]+=d;
}
int sum=0;
for(int i=1;i<=n*m;i++)
{
if(mat[i]==-1)
continue;
sum+=w[mat[i]][i];
}
return -sum;
}
int main()
{
scanf("%d",&ca);
while(ca--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&martix[i][j]);
init();
printf("%lf\n",KM()/(1.0*n));
}
return 0;
}