[SCOI2007]修車,洛谷P2053,最小費用最大流
阿新 • • 發佈:2018-12-04
正題
給出m個師傅,n臺車,並給出每個師傅各個車的時間,現在要使得,n輛車一起來,等待時間最短。
我們來觀察一個師傅所消耗的等待時間。m個師傅所消耗的總等待時間就是車主的總等待時間。
對於第a個師傅,修的車的序列是,那麼總等待時間就是,因為第i個車要被自己和後面的車等待,所以會被算tot-i+1次。
那麼建圖就是分顯而易見了,對於m個師傅,每個師傅拆n個點,第a個師傅的第i個點表示的是第a個師傅修倒數第i輛車。那麼n個點表示車。
倒數第1輛車只會被自己等待,所以從這點連向每一輛車j,表示可以修這一輛車,流量為1,費用為。
倒數第2輛車會被等待兩次,所以從這個點連向每一輛車j,流量為1,費用為
......
那麼最後我們從源點流量為1,費用為0的邊向所有時間段的師傅。從每一輛車連流量為1,費用為0的邊向匯點。
最小費用最大流跑一下。
Done.
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<queue> using namespace std; struct edge{ int x,y,next,c,cos; }s[100010]; int n,m; int len=1; int begin,end; int d[1210],mmin[1210],last[1210],first[1210]; bool tf[1210]; queue<int> f; void ins(int x,int y,int c,int cos){ len++; s[len]=(edge){x,y,first[x],c,cos};first[x]=len; len++; s[len]=(edge){y,x,first[y],0,-cos};first[y]=len; } bool SPFA(int &cost,int&flow){ memset(d,63,sizeof(d)); memset(tf,false,sizeof(tf)); memset(mmin,63,sizeof(mmin)); memset(last,0,sizeof(last)); f.push(begin);d[begin]=0;tf[begin]=true; while(!f.empty()){ int x=f.front();f.pop();tf[x]=false; for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(d[y]>d[x]+s[i].cos && s[i].c>0){ mmin[y]=min(mmin[x],s[i].c); d[y]=d[x]+s[i].cos; last[y]=i; if(!tf[y]){ tf[y]=true; f.push(y); } } } } if(d[end]==d[end+1]) return false; cost+=d[end]*mmin[end]; flow+=mmin[end]; int now=end; while(now!=begin){ s[last[now]].c-=mmin[end]; s[last[now]^1].c+=mmin[end]; now=s[last[now]].x; } return true; } void MCMF(){ int cost=0,flow=0; while(SPFA(cost,flow)); printf("%.2lf\n",(double)cost/n); } int main(){ scanf("%d %d",&m,&n); begin=0,end=n*m+n+1; int type=n*m; int c; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&c); for(int k=1;k<=n;k++) ins((j-1)*n+k,type+i,1,k*c); } } for(int i=1;i<=type;i++) ins(begin,i,1,0); for(int i=type+1;i<end;i++) ins(i,end,1,0); MCMF(); }