Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 5763 | Accepted: 2380 |
Description
The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The manager knows that every order will take different amount of hours in different workshops. More precisely, the i-th order will take Zij hours if the toys are making in the j-th workshop. Moreover, each order's work must be wholly completed in the same workshop. And a workshop can not switch to another order until it has finished the previous one. The switch does not cost any time.
The manager wants to minimize the average of the finishing time of the N orders. Can you help him?
Input
The first line of input is the number of test case. The first line of each test case contains two integers, N and M (1 ≤ N,M ≤ 50).
The next N lines each contain M integers, describing the matrix Zij (1 ≤ Zij ≤ 100,000) There is a blank line before each test case.
Output
For each test case output the answer on a single line. The result should be rounded to six decimal places.
Sample Input
3 3 4 100 100 100 1 99 99 99 1 98 98 98 1 3 4 1 100 100 100 99 1 99 99 98 98 1 98 3 4 1 100 100 100 1 99 99 99 98 1 98 98
Sample Output
2.000000 1.000000 1.333333
Source
有n个订单m个车间,每个车间均可以单独完成任何一个订单。每个车间完成不同订单的时间是不同的。不会出现两个车间完成同一个订单的情况。给出每个订单在某个车间完成所用的时间。问订单完成的平均时间是多少。
解题思路:
1、这个题在建图上有一些需要思考很长时间的地方。因为每个订单所消耗的时间是车间完成订单的时间加上订单等待的时间。我们设在车间A需要完成k个订单,消耗的总时间是t1+(t1+t2)+(t1+t2+t3)……转换一下就是t1*k+t2*(k-1)+t3*(k-3)……我们就找到了规律:当第i个订单在第j个车间是倒数第k个任务时,总消耗时间需要加上订单i在车间对应消耗时间的k倍。
2、建图的时候记得用负值来建图,这样顶标数组初始化成0就行了。因为不会有比0大的值出现。
3、结果出来后取相反数,然后除以n来得到最后的结果。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define INF 0x3f3f3f
const int maxn=55;
int n,m;
int nx,ny;
int lx[maxn],ly[maxn*maxn],match[maxn*maxn],slack[maxn*maxn];
bool visx[maxn],visy[maxn*maxn];
int edge[maxn][maxn*maxn],s[maxn][maxn];
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int min(int a,int b)
{
if(a<b)
return a;
else
return b;
}
bool dfs(int x)
{
visx[x]=true;
for(int y=0;y<ny;y++)
{
if(visy[y])
continue;
int tmp=lx[x]+ly[y]-edge[x][y];
if(tmp==0)
{
visy[y]=true;
if(match[y]==-1||dfs(match[y]))
{
match[y]=x;
return true;
}
}
else{
slack[y]=min(slack[y],tmp);
}
}
return false;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(ly,0,sizeof(ly));
for(int i=0;i<nx;i++)
{
lx[i]=-INF;
for(int j=0;j<ny;j++)
{
lx[i]=max(lx[i],edge[i][j]);
}
}
for(int x=0;x<nx;x++)
{
for(int i=0;i<ny;i++)
{
slack[i]=INF;
}
while(true)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(x))
break;
int d=INF;
for(int i=0;i<ny;i++)
{
if (!visy[i])
d = min(d, slack[i]);
}
for(int i=0;i<nx;i++)
{
if (visx[i])
lx[i] -= d;
}
for(int i=0;i<ny;i++)
{
if(visy[i])
ly[i]+=d;
else
slack[i]-=d;
}
}
}
int ans=0;
for(int i=0;i<ny;i++)
{
if(match[i]!=-1)
ans+=edge[match[i]][i];
}
return -ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&s[i][j]);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<m;k++)
{
edge[i][k*n+j]=-s[i][k]*(j+1);//第i个订单在第k个工厂生产,且在第k个工厂中生产的所有订单中它排在倒数第j位被生产
//因为这里是求最小值,而km算法是求最大权值的,所以要取负号
}
}
}
m*=n;
nx=n;
ny=m;
//printf("%d\n",KM());
printf("%.6lf\n",1.0*KM()/n);
}
return 0;
}
km模板可以看一下这个博客(这个大佬讲得挺好理解的):
https://www.cnblogs.com/wenruo/p/5264235.html