��վ�ܷ�������

网络流——修车(巨坑)

一开始就被题目坑了

每个人可以同时修车mmp每个人可以修多辆车

所以要进行拆点操作

每个人修n辆车,记第i个人修第j辆用时w(i,j)每人修倒数第k辆费用(权值)为w(i,j)* k,表示共有k辆车在等这辆车修故要乘起来。emmmmm很强的操作

然后再普通连二分图

车1–n再一遍,人共n* m个在另一边
完成

#include <bits/stdc++.h>
#define N 1000003
#define MAX 0x3f3f3f3f
using namespace std;
int head[N],deep[N],pre[N],dis[N],minn[N];
int st,ed,cnt,n,m,sum,flag[N],ans_flow,ans_cost,a[N],k;
struct node
{
    int to,w,fr,cost;
    int next=-1;
}edge[N];

inline void add(int u, int v, int k,int cc)
 {
    edge[cnt].fr = u, edge[cnt].to = v, edge[cnt].w = k;edge[cnt].cost=cc;
    edge[cnt].next = head[u], head[u] = cnt++;
    edge[cnt].fr = v, edge[cnt].to = u, edge[cnt].w = 0;edge[cnt].cost=-cc;
    edge[cnt].next = head[v], head[v] = cnt++;
}

bool SPFA(int s,int t)
{
    queue<int> q;
    memset(flag,0,sizeof(flag));
    memset(pre,-1,sizeof(pre));
    memset(dis,MAX,sizeof(dis));
    q.push(s);
    flag[s]=1;
    dis[s]=0;
    minn[s]=MAX;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        flag[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int kk=edge[i].to;
            if(edge[i].w>0&&dis[kk]>dis[u]+edge[i].cost)
            {
                dis[kk]=dis[u]+edge[i].cost;
                minn[kk]=min(edge[i].w,minn[u]);
                pre[kk]=i;
                if(!flag[kk])
                {
                    q.push(kk);
                    flag[kk]=1;

                }
            }

        }
    }
    if(dis[t]!=MAX)return 1;
    else return 0;

}
void dfs(int s,int t)
{
    int x=t;
    while(x!=s)
    {
        int i=pre[x];
        edge[i].w-=minn[t];
        edge[i^1].w+=minn[t];
        x=edge[i^1].to;
    }
    ans_flow+=minn[t];
    ans_cost+=dis[t]*minn[t];


}
void EK()
{
    while(SPFA(st,ed))
      dfs(st,ed);
}
int mp[500][500];
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&m,&n);
    st=0;ed=1000;
    for(int i=1;i<=n;i++)add(st,i,1,0);
    for(int i=n+1;i<=n+n*m;i++)add(i,ed,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
       scanf("%d",&mp[i][j]);
    for(int i=1;i<=n;i++)
    {
        int peo=1,num=0;
        for(int j=n+1;j<=n+n*m;j++)
        {
            num++;
            if(num>n){num=1;peo++;}
            add(i,j,1,mp[i][peo]*num);//mp[i][peo]表示这车被这个人倒数第num个修

        }
    }
    EK();
    printf("%.2lf",(double)ans_cost/(n*1.0));
    return 0;
}