n,m位置有毒
/************************************************************** Problem: 1070 User: lxy8584099 Language: C++ Result: Accepted Time:588 ms Memory:4084 kb ****************************************************************/ /* 费用流 。。。 可以把每个工人拆成m个 如果走第一个表示工人第一个修这辆车 然后就是跑一边最小费用最大流。。。 n 顾客 m技术人员 */ #include<queue> #include<cstdio> #include<cstring> using namespace std; const int N=2050; struct pp {int v,nxt,c,d;} e[N*100]; int n,m,st,ed,tot=1,from[N],dis[N],ans,head[N]; bool vis[N]; int min(int a,int b) {return a>b?b:a;} void add(int u,int v,int c,int d) { e[++tot].nxt=head[u];head[u]=tot; e[tot].v=v;e[tot].c=c;e[tot].d=d; e[++tot].nxt=head[v];head[v]=tot; e[tot].v=u;e[tot].c=0;e[tot].d=-d; } bool spfa() { memset(dis,0x3f,sizeof(dis)); dis[st]=0; queue<int> q;q.push(st); while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; for(int j=head[u];j;j=e[j].nxt) if(e[j].c>0) { int v=e[j].v,d=e[j].d; if(dis[v]>dis[u]+d) { dis[v]=dis[u]+d; from[v]=j; if(!vis[v]) vis[v]=1,q.push(v); } } } if(dis[ed]==dis[0]) return 0; int mn=dis[0]; for(int i=ed,j;i!=st;i=e[j^1].v) j=from[i],mn=min(mn,e[j].c); ans+=dis[ed]*mn; for(int i=ed,j;i!=st;i=e[j^1].v) j=from[i],e[j].c-=mn,e[j^1].c+=mn; return 1; } int main() { scanf("%d%d",&m,&n); st=n*m+n+1;ed=st+1; for(int i=1;i<=n;i++) add(st,n*m+i,1,0); for(int i=1;i<=n*m;i++) add(i,ed,1,0); for(int i=1;i<=n;i++) for(int j=1,x;j<=m;j++) { scanf("%d",&x); for(int k=1;k<=n;k++) add(n*m+i,(k-1)*m+j,1,x*k); } while(spfa()); printf("%.2lf\n",(double)(ans)/n); return 0; }