得 先 把 题 意 转 化 一 下 , 否 则 无 法 建 图 得先把题意转化一下,否则无法建图 得先把题意转化一下,否则无法建图
为 啥 没 办 法 建 图 ? 因 为 每 个 师 傅 修 每 辆 车 的 代 价 不 是 为啥没办法建图?因为每个师傅修每辆车的代价不是 为啥没办法建图?因为每个师傅修每辆车的代价不是定值
不 是 定 值 , 就 想 办 法 变 成 定 值 。 不是定值,就想办法变成定值。 不是定值,就想办法变成定值。
考 虑 某 个 师 傅 一 次 修 车 a 1 , a 2 , a 3 , a 4 考虑某个师傅一次修车a_1,a_2,a_3,a_4 考虑某个师傅一次修车a1,a2,a3,a4
那 么 a 1 的 等 待 时 间 是 a 1 那么a_1的等待时间是a_1 那么a1的等待时间是a1
a 2 的 等 待 时 间 是 a 1 + a 2 a_2的等待时间是a_1+a_2 a2的等待时间是a1+a2
a 3 的 等 待 时 间 是 a 1 + a 2 + a 3 a_3的等待时间是a_1+a_2+a_3 a3的等待时间是a1+a2+a3
a 4 的 等 待 时 间 是 a 1 + a 2 + a 3 + a 4 a_4的等待时间是a_1+a_2+a_3+a_4 a4的等待时间是a1+a2+a3+a4
设 某 个 师 傅 修 了 x 辆 车 设某个师傅修了x辆车 设某个师傅修了x辆车
最 后 修 的 车 的 代 价 只 需 要 在 原 来 基 础 上 乘 1 最后修的车的代价只需要在原来基础上乘1 最后修的车的代价只需要在原来基础上乘1
倒 数 第 二 次 修 车 的 代 价 只 需 要 在 原 来 的 基 础 上 乘 2 倒数第二次修车的代价只需要在原来的基础上乘2 倒数第二次修车的代价只需要在原来的基础上乘2
. . . . . . . . . . . . . . . . . . . . . . ...................... ......................
于 是 把 m 个 师 傅 分 成 n 层 于是把m个师傅分成n层 于是把m个师傅分成n层
第 i 层 表 示 修 倒 数 第 i 辆 车 的 师 傅 , 那 么 代 价 乘 以 i 第i层表示修倒数第i辆车的师傅,那么代价乘以i 第i层表示修倒数第i辆车的师傅,那么代价乘以i
每 层 的 每 个 师 傅 向 每 一 辆 车 连 边 即 可 每层的每个师傅向每一辆车连边即可 每层的每个师傅向每一辆车连边即可
跑 最 小 费 用 最 大 流 , 对 于 每 个 师 傅 而 言 一 定 是 依 次 选 择 跑最小费用最大流,对于每个师傅而言一定是依次选择 跑最小费用最大流,对于每个师傅而言一定是依次选择
修 倒 数 第 1 辆 车 , 修 倒 数 第 2 辆 车 , 实 际 上 这 也 是 连 续 的 修倒数第1辆车,修倒数第2辆车,实际上这也是连续的 修倒数第1辆车,修倒数第2辆车,实际上这也是连续的
#include
using namespace std;
const int maxn=2e5+10;
const int inf=1e9;
int n,m,s,t,c[509][509];
struct edge{
int to,nxt,flow,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w,int flow){
d[++cnt]=(edge){v,head[u],flow,w},head[u]=cnt;
d[++cnt]=(edge){u,head[v],0,-w},head[v]=cnt;
}
int dis[maxn],mincost,vis[maxn],pre[maxn],flow[maxn];
bool spfa()
{
for(int i=0;i<=t;i++) dis[i]=inf,vis[i]=0;
dis[s]=0,flow[s]=inf;
queueq; q.push( s );
while( !q.empty() )
{
int u=q.front(); q.pop();
vis[u]=0;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( d[i].flow&&dis[v]>dis[u]+d[i].w )
{
dis[v]=dis[u]+d[i].w;
flow[v]=min(flow[u],d[i].flow);
pre[v]=i;
if( !vis[v] ) vis[v]=1,q.push( v );
}
}
}
return dis[t]!=inf;
}
int dinic()
{
while( spfa() )
{
int x=t;
mincost+=flow[t]*dis[t];
while( x!=s )
{
int i=pre[x];
d[i].flow-=flow[t];
d[i^1].flow+=flow[t];
x=d[i^1].to;
}
}
}
int main()
{
cin >> m >> n;//m位技术人员,n位车主
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >> c[i][j];
s=0,t=n*m+n+1;
for(int i=1;i<=n*m;i++) add(s,i,0,1);//源点连向每个师傅
for(int i=1;i<=m;i++)//枚举每个师傅
for(int j=1;j<=n;j++)//枚举每个车
for(int k=1;k<=n;k++)//枚举每个时刻
{
int id=(k-1)*m+i;//第k层图,每层图有m个师傅
add(id,j+n*m,c[j][i]*k,1);
}
for(int i=1;i<=n;i++) add(n*m+i,t,0,1);
dinic();
printf("%.2lf",double(mincost)/(n*1.0) );
}