![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define M 1005 #define inf 0x7fffffff #define T 601 struct edge{int to,next,cap,val;}e[100001]; int n,m,t[61][10]; int head[M],dis[M]; int cnt=1; void add(int u,int v,int w,int q){ e[++cnt].to=v;e[cnt].next=head[u];e[cnt].cap=w;e[cnt].val=q;head[u]=cnt; e[++cnt].to=u;e[cnt].next=head[v];e[cnt].cap=0;e[cnt].val=-q;head[v]=cnt; } int S=0,mark[M]; int ans=0; bool bfs() { memset(mark,0,sizeof(mark)); for(int i=0;i<=T;i++)dis[i]=inf; dis[S]=0;mark[S]=1; queue<int> q; q.push(S); while(!q.empty()) { int now=q.front();q.pop(); for(int i=head[now];i;i=e[i].next) if(e[i].cap&&dis[e[i].to]>dis[now]+e[i].val) { dis[e[i].to]=dis[now]+e[i].val; if(!mark[e[i].to]) {mark[e[i].to]=1;q.push(e[i].to);} } mark[now]=0; } if(dis[T]==inf)return 0; return 1; } int dfs(int x,int f) { if(x==T){mark[T]=1;return f;} int used=0,w; mark[x]=1; for(int i=head[x];i;i=e[i].next) if(!mark[e[i].to]&&e[i].cap&&dis[x]+e[i].val==dis[e[i].to]) { w=f-used; w=dfs(e[i].to,min(e[i].cap,w)); ans+=w*e[i].val; e[i].cap-=w;e[i^1].cap+=w; used+=w;if(used==f)return f; } return used; } void wya() { while(bfs()) { mark[T]=1; while(mark[T]) { memset(mark,0,sizeof(mark)); dfs(0,inf); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&t[i][j]); for(int i=1;i<=n*m;i++) add(0,i,1,0); for(int i=n*m+1;i<=n*m+m;i++) add(i,T,1,0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++) add((i-1)*m+j,n*m+k,1,t[k][i]*j); wya(); printf("%.2lf",(double)ans/m); return 0; }
之前不知知道为什么都是反着写的,这会正过来也对了。也没有多玄啊。