一开始就被题目坑了
每个人可以同时修车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;
}