【BZOJ 1070】[SCOI2007]修车 费用流
就是拆个点限制一下(两点一排一大片),这道题让我注意到了限制这个重要的词。我们跑网络流跑出来的图都是有一定意义的,一般这个意义就对应了问题的一种方案,一般情况下跑一个不知道对不对的方案是相对容易的我们要做的就是尽可能去限制他,使他正确,有的时候(特别是费用流)我们也要使他计算答案更加简便。
#include <cstdio> #include <cstring> #include <algorithm> #define car(a) (a) #define tech(a,b) ((a)*n+(b)) const int N=65; const int M=10; const int P=N*M; const int E=N*N*M*2; const int Inf=0x3f3f3f3f; struct V{ int to,next,c,f; }c[E]; int head[P],t=1; inline void add(int x,int y,int z,int _){ c[++t].to=y,c[t].f=z,c[t].c=_,c[t].next=head[x],head[x]=t; } int dis[P],anc[P],S,T,n,m; int q[P],front,back; bool in[P]; int ans; inline bool spfa(){ memset(dis,0x3f,sizeof(dis)); dis[S]=0,in[S]=true,q[back++]=S; if(back==P)back=0; while(front!=back){ int x=q[front++];in[x]=false; if(front==P)front=0; for(int i=head[x];i;i=c[i].next) if(c[i].f&&c[i].c+dis[x]<dis[c[i].to]){ dis[c[i].to]=dis[x]+c[i].c,anc[c[i].to]=i; if(!in[c[i].to]){ q[back++]=c[i].to,in[c[i].to]=true; if(back==P)back=0; } } } return dis[T]!=Inf; } inline int shoot(){ int f=Inf; for(int i=anc[T];i;i=anc[c[i^1].to])f=std::min(f,c[i].f); for(int i=anc[T];i;i=anc[c[i^1].to])c[i].f-=f,c[i^1].f+=f; return f*dis[T]; } int main(){ scanf("%d%d",&m,&n); S=n*m+n+1,T=S+1; for(int i=1;i<=n;++i){ add(S,car(i),1,0); add(car(i),S,0,0); } for(int i=1,x;i<=n;++i) for(int j=1;j<=m;++j){ scanf("%d",&x); for(int k=1;k<=n;++k){ add(car(i),tech(j,k),1,k*x); add(tech(j,k),car(i),0,-k*x); } add(tech(j,i),T,1,0); add(T,tech(j,i),0,0); } while(spfa())ans+=shoot(); printf("%.2f",(double)ans/(double)n); return 0; }
苟利国家生死以, 岂因祸福避趋之。