建图重要。
m个工人, n辆车
源点向每辆车连一条容量为1费用为0的边。
把每个工人拆成n个,第i个工人的第j个节点表示,第i个工人修倒数j辆车。
每辆车向这n*m个工人连一条容量为1费用为这个工人修这辆车的时间*这个工人倒数第几个修这辆车。
因为修一辆车只会使在它后面修的都+修这辆车的时间。
//我服了,烂费用流板子,一直t,狗了一个别人的spfa,才过。我就吐槽一句,是谁教我的费用流!?
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n, m, shi[15][65], huan, hui,tot;
int tp = 1, dis[100000], vis[100000], tov[100000], tof[100000], tow[100000], h[100000], nex[100000], fa[100000], bian[100000];
double ans;
deque<int> q;
void read(int &x)
{
x = 0;
int f = 0;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = 1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
if(f) x = -x;
}
void add(int x,int y,int w,int f)
{
tp++;
tov[tp] = y;
tow[tp] = w;
tof[tp] = f;
nex[tp] = h[x];
h[x] = tp;
tp++;
tov[tp] = x;
tow[tp] = 0;
tof[tp] = -f;
nex[tp] = h[y];
h[y] = tp;
}
/*bool spfa()
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(q,0,sizeof(q));
int head = 0, tail = 1;
dis[huan] = 0;
q[tail] = huan;
vis[huan] = 1;
while(head < tail)
{
head++;
int x = q[head];
for(int i = h[x]; i; i = nex[i])
{
tot++;
int v = tov[i];
if(dis[v] > dis[x] + tof[i] && tow[i] != 0)
{
dis[v] = dis[x] + tof[i];
fa[v] = x;
bian[v] = i;
if(vis[v] == 0)
{
vis[v] = 1;
tail++;
q[tail] = v;
}
}
}
vis[x] = 0;
}
return dis[hui] == dis[hui+1] ? 0 : 1;
}
*/
bool spfa(int s,int e)
{
memset(dis,63,sizeof(dis));
dis[s] = 0;
vis[s] = 1;
q.push_front(s);
while(q.size())
{
int f = q.front(); q.pop_front();
vis[f] = 0;
for(int i = h[f];i;i = nex[i])
{
int v = tov[i];
if(tow[i] && dis[v] > dis[f] + tof[i])
{
dis[v] = dis[f] + tof[i];
bian[v] = i;
fa[v]= f;
if(!vis[v])
{
vis[v] = 1;
if(q.empty() || dis[v] < dis[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
if(dis[e] == dis[e+2]) return false;
return true;
}
int liu()
{
int u=hui;
int delta=1e9;
while(u!=huan)
{
delta=min(delta,tow[bian[u]]);
u=fa[u];
}
u=hui;
while(u!=huan)
{
tow[bian[u]]-=delta;
tow[bian[u]^1]+=delta;
u=fa[u];
}
return dis[hui];
}
int main()
{
int haha = 1;
read(m);read(n);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
read(shi[j][i]);
}
huan = 0;
hui = n + m * n + 1;
for(int i = 1; i <= n; i++)
{
add(huan, i, 1,0);
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
for(int k = 1; k <= n; k++)
add(i,n+(j-1)*n+k,1,k * shi[j][i]);
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
add(n+(i-1)*n + j, hui,1,0);
while(spfa(huan,hui))
{
ans += liu();
}
printf("%0.2lf",ans/n);
//cout <<tot ;
return 0;
}