题意: 一共有 n 个任务, m 台机器, 知道了每个机器处理每个任务的时间,一个任务只有在处理完之后才能处理其他任务,问你最少需要多少时间,
才能做完所有的任务。
分析: 以 任务为 X 集合 第 i 个任务在第 j 台机器 倒数第 k 个完成为 Y 集合,找到完全匹配下的最小权匹配,此题构图方法依然是 拆点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<stdio.h> #include<string.h> #define INF 0x1f1f1f #define clr(x)memset(x,0,sizeof(x)) int sx[55],sy[2550]; int lx[55],ly[2550]; int link[2550]; int lix[55]; int map[55][2550]; int n,m; int find(int x) { int i; sx[x]=1; for(i=1;i<=m;i++) if(!sy[i]&&lx[x]+ly[i]==map[x][i]) { sy[i]=1; if(link[i]==0||find(link[i])) { lix[x]=i; link[i]=x; return 1; } } return 0; } int KM() { int i,j,v,sum,dmin; clr(ly); for(i=1;i<=n;i++) for(j=1;j<=m;j++) map[i][j]=-map[i][j]; for(i=1;i<=n;i++) { lx[i]=-INF; for(j=1;j<=m;j++) if(map[i][j]>lx[i]) lx[i]=map[i][j]; } clr(link); for(v=1;v<=n;v++) { clr(sx); clr(sy); while(1) { if(find(v)) break; dmin=INF; for(i=1;i<=n;i++) if(sx[i]) for(j=1;j<=m;j++) if(!sy[j]&&lx[i]+ly[j]-map[i][j]<dmin) dmin=lx[i]+ly[j]-map[i][j]; for(i=1;i<=n;i++) if(sx[i]) {lx[i]-=dmin;sx[i]=0;} for(i=1;i<=m;i++) if(sy[i]) { ly[i]+=dmin;sy[i]=0;} } } sum=0; for(i=1;i<=n;i++) sum-=map[i][lix[i]]; return sum; } int a[55][55]; int main() { int t,i,j,k; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&a[i][j]); for(k=1;k<=n;k++) for(i=1;i<=m;i++) for(j=1;j<=n;j++) map[k][(i-1)*n+j]=a[k][i]*j; m=n*m; printf("%.6lf\n",(double)KM()/(double)n); } return 0; }