[SCOI2007]修车 BZOJ1070
很久之前写的题了,今天翻出来写一篇博客复习一下...
分析:
考虑,T <= 1000,并不能针对这一维处理,所以考虑将,每个人拆点,之后,拆完之后表示,这个人第n-j+1个修k这辆车,也就是,m*(i-1)+j向n*m+k连边,流量为1,费用为t[i][k]*j,之后建图跑费用流。
BZOJ上我之前跑过去了,但是现在改时间限制了...现在跑不过了...不过luogu上没有问题...
附上代码:
#include <cstdio> #include <algorithm> #include <iostream> #include <queue> #include <cmath> #include <cstring> using namespace std; #define N 2005 #define S 0 #define T 2004 int head[N],cnt,n,m; struct node { int to,next,val,flow,from; }e[N*40]; inline void add(int x,int y,int z,int v) { e[cnt].from=x; e[cnt].to=y; e[cnt].next=head[x]; e[cnt].val=v; e[cnt].flow=z; head[x]=cnt++; e[cnt].from=y; e[cnt].to=x; e[cnt].next=head[y]; e[cnt].val=-v; e[cnt].flow=0; head[y]=cnt++; return ; } int vis[N],dis[N],que[N]; int fro[N]; int spfa() { memset(fro,-1,sizeof(fro)); memset(dis,0x3f,sizeof(dis)); int l=0,r=0; que[r++]=S; vis[S]=1; dis[S]=0; while(l<r) { int x=que[l++]; vis[x]=0; for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(e[i].flow&&dis[to1]>dis[x]+e[i].val) { dis[to1]=dis[x]+e[i].val; fro[to1]=i; if(!vis[to1]) { que[r++]=to1; vis[to1]=1; } } } } if(dis[T]>(1<<25)) { return 0; } return 1; } inline void update(int i,int c) { e[i].flow-=c; e[i^1].flow+=c; return ; } int ans; void mcf() { int i,x=1<<30; i=fro[T]; while(i!=-1) { x=min(e[i].flow,x); i=fro[e[i].from]; } i=fro[T]; while(i!=-1) { e[i].flow-=x; e[i^1].flow+=x; ans+=x*e[i].val; i=fro[e[i].from]; } } int t[105][105]; int main() { for(int i=0;i<N;i++) { head[i]=-1; } scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) { for(int j=1;j<=m;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+n;i++) { add(i,T,1,0); } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { for(int k=1;k<=n;k++) { add((i-1)*n+j,m*n+k,1,t[k][i]*j); } } } while(spfa()) { mcf(); } printf("%.2lf\n",(1.0*ans)/(1.0*n)); return 0; }