BZOJ 1070 [SCOI2007]修车
费用流。。一开始以为是贪心,后来看见数据范围,就想别的了。。。
这题又是考构图的,省选的构图都好难啊。。。有没有想到。。
关键就是把每个技术员拆成n个点,表示这个技术员倒数第几个修的车子。。
考虑第i个工人,他修第j辆车只对后面要修的车有影响,而前面修过的车已经对当前没有影响了。
而这个影响就是后面每个将要修理的车都多等待了time的时间。
太绝了!
View Code
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 #include <algorithm> 6 7 #define N 10000 8 #define M 200000 9 #define INF 1e9 10 11 using namespace std; 12 13 int head[N],next[M],to[M],len[M],pr[M]; 14 int n,m,cnt,S,T,mlen; 15 int tim[1000][1000]; 16 int dis[N],pre[N],q[M]; 17 bool vis[N]; 18 19 inline void add(int u,int v,int r,int w) 20 { 21 to[cnt]=v; len[cnt]=r; pr[cnt]=w; next[cnt]=head[u]; head[u]=cnt++; 22 to[cnt]=u; len[cnt]=0; pr[cnt]=-w; next[cnt]=head[v]; head[v]=cnt++; 23 } 24 25 inline void read() 26 { 27 memset(head,-1,sizeof head); cnt=0; 28 scanf("%d%d",&m,&n); 29 S=0; T=n+n*m+1; 30 for(int i=1,a;i<=n;i++) 31 for(int j=1;j<=m;j++) 32 scanf("%d",&tim[i][j]); 33 for(int i=1;i<=n;i++) add(S,i,1,0); 34 for(int i=n+n*m;i>=n+1;i--) add(i,T,1,0); 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=m;j++) 37 for(int k=1;k<=n;k++) 38 add(i,j*n+k,1,(n-k+1)*tim[i][j]); 39 } 40 41 inline bool spfa() 42 { 43 memset(pre,-1,sizeof pre); 44 memset(dis,0x3f,sizeof dis); 45 int h=1,t=2,sta; 46 q[1]=S; dis[S]=0; vis[S]=true; 47 while(h<t) 48 { 49 sta=q[h++]; vis[sta]=false; 50 for(int i=head[sta];~i;i=next[i]) 51 if(len[i]&&dis[to[i]]>dis[sta]+pr[i]) 52 { 53 dis[to[i]]=dis[sta]+pr[i]; 54 pre[to[i]]=i; 55 if(!vis[to[i]]) q[t++]=to[i],vis[to[i]]=true; 56 } 57 } 58 return pre[T]!=-1; 59 } 60 61 inline void updata() 62 { 63 mlen=INF; 64 for(int i=pre[T];~i;i=pre[to[i^1]]) 65 mlen=min(mlen,len[i]); 66 for(int i=pre[T];~i;i=pre[to[i^1]]) 67 len[i]-=mlen,len[i^1]+=mlen; 68 } 69 70 inline void go() 71 { 72 int ans=0; 73 while(spfa()) updata(),ans+=dis[T]*mlen; 74 printf("%.2lf\n",double(ans)/n); 75 } 76 77 int main() 78 { 79 read(); 80 go(); 81 return 0; 82 }
没有人能阻止我前进的步伐,除了我自己!