/**//* 题意:有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
搜索
最新评论
|
|