 /**//*
题意:有N个工件要在M个机器上加工,有一个N*M的矩阵描述其加工时间。
同一时间内每个机器只能加工一个工件,问加工完所有工件后,使得平均加工时间最小。

将工件作为二分图中X部的点,总共N个。
将每个机器拆成N个点作为二分图中Y部的点,总共N*M个。
第J个机器的第P个点代表,使用机器 J进行倒数第P次加工。
假设我们按顺序在J机器上工件I1,I2,I3..IK个工件,则总共需要花费I1*K+I2*(K- 1)+I3*(K-3)+ +IK。
所以我们对于X中每个点I,Y中每个点(J,P),连接一条A[I,J]*P权值的边。
接下来进行二分图最佳匹配即可。
*/
#include<cstdio>
#include<cstring>

const int MAXN=55;
const int INF=1000000000;

int n,m;
int g[MAXN][MAXN*MAXN];
int data[MAXN][MAXN];
int lx[MAXN],ly[MAXN*MAXN];//可行顶标
int cx[MAXN],cy[MAXN*MAXN];//匹配边集
bool sx[MAXN],sy[MAXN*MAXN];

 bool path(int u) {//扩展二分图 判断是否存在由行元素u出发的可增广路径
sx[u]=1;
 for(int v=1;v<=m;v++) {
 if(g[u][v]==lx[u]+ly[v]&&!sy[v]) {
sy[v]=1;
 if(cy[v]==0||path(cy[v])) {
cx[u]=v;cy[v]=u;
return true;
}
}
}
return false;
}
 int KM() {
memset(ly,0,sizeof(ly));
memset(cx,0,sizeof(cx));
memset(cy,0,sizeof(cy));
 for(int i=1;i<=n;i++) {
lx[i]=-INF;
for(int j=1;j<=m;j++)
if(lx[i]<g[i][j])lx[i]=g[i][j];
}
 for(int u=1;u<=n;u++) {
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
 while(!path(u)) {
int Min=INF;
 for(int i=1;i<=n;i++) {
if(!sx[i])continue;
for(int j=1;j<=m;j++)
if(!sy[j]&&lx[i]+ly[j]-g[i][j]<Min)
Min=lx[i]+ly[j]-g[i][j];
}
//调整顶标,二分图撤去该元素
for(int i=1;i<=n;i++)
 if(sx[i]) {lx[i]-=Min;sx[i]=false;}
for(int i=1;i<=m;i++)
 if(sy[i]) {ly[i]+=Min;sy[i]=false;}
}
}
int ans=0;
for(int i=1;i<=n;i++)
ans+=g[i][cx[i]];
return ans;
}
 int main() {
int T;
scanf("%d",&T);
 while(T--) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&data[i][j]);
//build
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
g[i][(j-1)*n+k]=-data[i][j]*k;//花费
m=n*m;
double ans=-1.0*KM()/n;
printf("%.6f\n",ans);
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|