题目链接
有n个订单m个车间,每个车间均可以单独完成任何一个订单。每个车间完成不同订单的时间是不同的。不会出现两个车间完成同一个订单的情况。给出每个订单在某个车间完成所用的时间。问订单完成的平均时间是多少。加上等待时间。
我们假设一个车间需要完成k个订单,消耗的总时间是t1+(t1+t2)+(t1+t2+t3)……转换一下就是t1*k+t2*(k-1)+t3*(k-3)……
可以想象,全部都在一个车间完成,那么消耗时间少的一定要在第一个完成,这个才能最大化节省时间。,
然后我们怎么建图呢?
假如有 m 个车间, n 个玩具,那么我们把每一个车间分成 n 个车间, 相当于总共 有 n * m 个车间。
每个车间只能生产一个玩具,
1 ~ n 就是1号车间。
然后每个 玩具生产时间 * i 向第 i 个点连一条容量为 1 的边,
依次类推,向所有的车间连边。
最后我们跑最小费用流。就一定可以找到一个最优解。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int INF = 0x3f3f3f3f;
const int N = 3e3;
const int M = 3e5;
struct edge{
int u,v,w,c;
}f[M];
int pre[N],Next[M],head[N],dis[N],flow[N];
int cnt,n,m,s,t,z[60][60];
bool vis[N];
void _Add(int u, int v, int w, int c){
cnt++;
Next[cnt] = head[u];
head[u] = cnt;
f[cnt].u = u;
f[cnt].v = v;
f[cnt].w = w;
f[cnt].c = c;
return;
}
void Add_edge(int u, int v, int w, int c ){
_Add(u,v,w,c);
_Add(v,u,0,-c);
return;
}
void init(){
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d",&z[i][j]);
s = 0; t = n + n * m + 1;
cnt = -1;
mem(head,-1);
for (int i = 1; i <= n; i++)
Add_edge(0,i,1,0);
for (int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
Add_edge(i * n + j,t,1,0);
for (int k = 1; k <= n; k++)
Add_edge(k,i * n + j,1,j * z[k][i]);
}
}
}
bool spfa(){
mem(pre,-1);
mem(dis,INF);
mem(flow,0);
mem(vis,0);
flow[0] = INF;
dis[0] = 0;
queue<int>q;
while(!q.empty()) q.pop();
q.push(0);
vis[0] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
vis[u] = 0;
for (int i = head[u]; i != -1; i = Next[i]){
int v = f[i].v;
if (f[i].w > 0 && dis[v] > dis[u] + f[i].c){
dis[v] = dis[u] + f[i].c;
flow[v] = min(flow[u],f[i].w);
pre[v] = i;
if (vis[v] == 0){
q.push(v);
vis[v] = 1;
}
}
}
}
if (pre[t] == -1) return 0;
return 1;
}
int min_cost_flow(){
int Ans = 0;
while(spfa()){
int now = t;
int last = pre[t];
while(now != 0){
f[last].w -= flow[t];
f[last ^ 1].w += flow[t];
now = f[last].u;
last = pre[now];
}
Ans += dis[t];
}
return Ans;
}
int main() {
int T;
cin>>T;
while(T--) {
init();
int Ans = min_cost_flow();
printf("%.6lf\n",(Ans*1.0)/n);
}
return 0;
}