bzoj1070: [SCOI2007]修车
飞机延误,被llj同学勤奋的精神感动到决定打一道水题。
费用流水题。
把技术人员拆成n个,每辆车连向第i个技术人员的第j个点代价是这辆车是第i技术员倒数第j个修的的代价。
源点向每辆车连,每个技术人员向汇点连。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=1e5+7,inf=0x7fffffff;
typedef long long LL;
using namespace std;
int n,m;
template<typename T> void read(T &x) {
T f=1; x=0; char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
struct edge {
int u,v,fl,cap,cost,nx;
edge(){}
edge(int u,int v,int fl,int cap,int cost,int nx):u(u),v(v),fl(fl),cap(cap),cost(cost),nx(nx){}
}e[N];
int fir[N],ecnt=1;
void add(int u,int v,int cap,int cost) {
e[++ecnt]=edge(u,v,0,cap,cost,fir[u]); fir[u]=ecnt;
e[++ecnt]=edge(v,u,0,0,-cost,fir[v]); fir[v]=ecnt;
}
int vis[N],dis[N],p[N],tot;
queue<int>que;
int spfa(int s,int t) {
for(int i=1;i<=tot;i++) vis[i]=0,dis[i]=inf;
que.push(s); dis[s]=0;
while(!que.empty()) {
int x=que.front();
que.pop(); vis[x]=0;
for(int i=fir[x];i;i=e[i].nx)
if(e[i].cap>e[i].fl) {
int y=e[i].v;
if(dis[y]>dis[x]+e[i].cost) {
dis[y]=dis[x]+e[i].cost;
p[y]=i;
if(!vis[y]) {
vis[y]=1;
que.push(y);
}
}
}
}
return dis[t]!=inf;
}
int calc(int s,int t) {
int fl=inf,res=0;
for(int i=t;i!=s;i=e[p[i]].u)
fl=min(fl,e[p[i]].cap-e[p[i]].fl),
res+=e[p[i]].cost;
for(int i=t;i!=s;i=e[p[i]].u)
e[p[i]].fl+=fl,e[p[i]^1].fl-=fl;
return fl*res;
}
int max_flow(int s,int t) {
int res=0;
while(spfa(s,t))
res+=calc(s,t);
return res;
}
int main() {
read(m); read(n);
int s=n*m+n+1;
int t=s+1; tot=t;
for(int i=1;i<=n;i++) {
int x=n*m+i;
add(s,x,1,0);
for(int j=1;j<=m;j++) {
int v;
read(v);
for(int k=1;k<=n;k++) {
int y=(k-1)*m+j;
add(x,y,1,k*v);
}
}
}
for(int i=1;i<=m;i++)
for(int k=1;k<=n;k++)
add((k-1)*m+i,t,1,0);
double ans=max_flow(s,t);
ans=ans/(1.0*n);
printf("%.2lf\n",ans);
return 0;
}