这是挑战上的一道题,不得不说十分的难懂。我看了好久才明白什么意思,当然好像跟挑战上的意思有点区别但是能A就行。
首先,我们知道,这些玩具是可以交给各个工厂去加工的,一个工厂可以加工多个工厂,这里还没什么头绪。
我们来看只有一个工厂的时候,加工n个玩具的总时间就会有T = Z1 + (Z1 + Z2) + .... + (Z1 + Z2 + .... + Zn)
也就是T = n * Z1 + (n - 1) * Z2 + ..... + 1 * Zn
我们可以从上式中看出一些东西,就是玩具i,假设他是在这个工厂里面第k个加工的,那么他就是上面的Zk
我们可以看到,Zk对总时间的贡献就是(n - k + 1) * Zk。
这时候我们就可以把每个工厂给拆点了,拆成了n个点,第k个点代表的是第k个加工。
我们要的是总共的时间最小,那么构图:
一个超级源点连向每个玩具,流量为1,花费为0.
每个工厂拆出来的点连向超级汇点,流量为1,花费为0.
每个玩具i和每个工厂j的第k个加工的点连一条流量为1,花费为(n-k+1)*G[i][j]的边,G[i][j]就是玩具i在j工厂加工的费用。
然后就跑一跑费用流输出即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<utility>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2600;
const int maxm = 260000;
int n, m;
int head[maxn], to[maxm], front[maxm], flow[maxm], cost[maxm], ppp;
int dis[maxn], minflow[maxn];
bool flag[maxn];
pair<int, int> par[maxn];
int G[55][55];
struct MIN_COST_MAX_FLOW{
void init() {
memset(head, -1, sizeof(head));
ppp = 0;
}
bool spfa(int s, int e)
{
int u, v;
for(int i = 0; i <= e; i++)
dis[i] = INF;
memset(flag, 0, sizeof(flag));
dis[s] = 0;
minflow[s] = INF;
queue <int> q;
q.push(s);
while(!q.empty())
{
u = q.front();
q.pop();
flag[u] = 0;
for(int i = head[u]; ~i; i = front[i])
{
v = to[i];
if(flow[i] && dis[v] > dis[u] + cost[i])
{
dis[v] = dis[u] + cost[i];
par[v] = (make_pair(u, i));
minflow[v] = min(minflow[u], flow[i]);
if(!flag[v])
{
flag[v] = 1;
q.push(v);
}
}
}
}
if(dis[e] == INF)
return 0;
return 1;
}
int slove(int s, int e)
{
int ans = 0, p;
while(spfa(s, e))
{
p = e;
while(p != s)
{
flow[par[p].second] -= minflow[e];
flow[par[p].second^1] += minflow[e];
p = par[p].first;
}
ans += dis[e];
}
return ans;
}
void add_edge(int u, int v, int f, int c)
{
to[ppp] = v, front[ppp] = head[u], flow[ppp] = f, cost[ppp] = c, head[u] = ppp++;
to[ppp] = u, front[ppp] = head[v], flow[ppp] = 0, cost[ppp] = -c, head[v] = ppp++;
}
}mcmf;
int main()
{
// freopen("poj_in.txt", "r", stdin);
int T;
cin >> T;
while(T--) {
mcmf.init();
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d", &G[i][j]);
}
}
int s = n + m * n + 1, t = s + 1;
for(int i = 0; i < n; i++) {
mcmf.add_edge(s, i, 1, 0);
}
for(int j = 0; j < m; j++) {
for(int k = 0; k < n; k++) {
mcmf.add_edge(n + j * n + k, t, 1, 0);
for(int i = 0; i < n; i++) {
mcmf.add_edge(i, n + j * n + k, 1, (n - k) * G[i][j]);
}
}
}
int ans = mcmf.slove(s, t);
printf("%.6f\n", (double)(ans) / n);
}
return 0;
}