[BZOJ1070][SCOI2007]修车 费用流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1070
这种资源分配,平衡下最优解的题目好多都可以建图跑。要把车分配给修车师傅这种模式,想到网络流,又因为要修的车数N不会变,相当于总流量固定,则考虑费用流。但是直接考虑师傅修车是不好做的,我们反过来考虑车被师傅修,接下来就是神奇的建图。
考虑车对答案的贡献,假设第i个车是第j个师傅修的倒数第k个车,于是它的贡献就是Ti[i][j]*k。
然后考虑第i个车对可能的情况连边,xjb建一建就出来了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 const int INF=1<<30; 7 int inline readint(){ 8 int Num;char ch; 9 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 10 while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0'; 11 return Num; 12 } 13 int N,M; 14 int Ti[65][15]; 15 int S,T; 16 int to[100000],ne[100000],c[100000],w[100000],fir[1000],cnt=0; 17 void add(int a,int b,int x,int y){ 18 to[cnt]=b,c[cnt]=x,w[cnt]=y,ne[cnt]=fir[a],fir[a]=cnt++; 19 to[cnt]=a,c[cnt]=0,w[cnt]=-y,ne[cnt]=fir[b],fir[b]=cnt++; 20 } 21 int dis[1000],pre[1000]; 22 bool in[1000]; 23 queue <int> q; 24 bool spfa(){ 25 memset(dis,127/3,sizeof(dis)); 26 dis[S]=0; 27 in[S]=true; 28 q.push(S); 29 int u; 30 while(!q.empty()){ 31 u=q.front(); 32 q.pop(); 33 in[u]=false; 34 for(int i=fir[u];i!=-1;i=ne[i]){ 35 int v=to[i]; 36 if(dis[v]>dis[u]+w[i]&&c[i]){ 37 dis[v]=dis[u]+w[i]; 38 pre[v]=i; 39 if(!in[v]){ 40 q.push(v); 41 in[v]=true; 42 } 43 } 44 } 45 } 46 return dis[T]!=dis[0]; 47 } 48 int Mcmf(){ 49 int cost=0; 50 pre[S]=-1; 51 while(spfa()){ 52 int f=INF; 53 for(int i=pre[T];i!=-1;i=pre[to[i^1]]) f=min(f,c[i]); 54 for(int i=pre[T];i!=-1;i=pre[to[i^1]]){ 55 c[i]-=f; 56 c[i^1]+=f; 57 } 58 cost+=f*dis[T]; 59 } 60 return cost; 61 } 62 int main(){ 63 M=readint(); 64 N=readint(); 65 for(int i=1;i<=N;i++) 66 for(int j=1;j<=M;j++) 67 Ti[i][j]=readint(); 68 memset(fir,-1,sizeof(fir)); 69 S=(M+1)*N+1; 70 T=(M+1)*N+2; 71 for(int i=1;i<=N;i++) add(S,N*M+i,1,0); 72 for(int i=1;i<=N*M;i++) add(i,T,1,0); 73 for(int i=1;i<=N;i++) 74 for(int j=1;j<=M;j++) 75 for(int k=1;k<=N;k++) 76 add(N*M+i,(j-1)*N+k,1,Ti[i][j]*k); 77 printf("%.2lf\n",(double)Mcmf()/N); 78 return 0; 79 }