1. 程式人生 > >bzoj 1070 修車 —— 費用流

bzoj 1070 修車 —— 費用流

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1070

需要考慮前面修的車對後面等待的車造成的時間增加;

其實可以從每個人修車的順序考慮,如果這輛車作為最後一輛被一個人修,那麼它對後面的車無影響,而每提前一位,影響時間就增加一份;

也就是如果確定一輛車是第幾個被修的,那麼它的影響就可以單獨確定;

費用流的選邊策略是先選費用小的,再選費用大的,正可以對應這個過程;

所以把每個人拆成 n 個點表示修車順序,然後車向對應的點連對應邊權的邊即可。

程式碼如下:

#include<cstdio>
#include<cstring>
#include
<algorithm> #include<queue> using namespace std; int const xn=605,xm=80005,inf=1e9; int n,m,hd[xn],ct=1,to[xm],nxt[xm],w[xm],c[xm],S,T; int dis[xn],pre[xn],inc[xn]; bool vis[xn]; queue<int>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } int Min(int x,int y){return x<y?x:y;} void ade(int x,int y,int z,int f){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; w[ct]=z; c[ct]=f;} void add(int x,int y,int z,int f){ade(x,y,z,f); ade(y,x,-z,0);} int id(int x,int tp) {
if(!tp)return m*n+x; return (x-1)*n+tp; } bool bfs() { for(int i=S;i<=T;i++)vis[i]=0; for(int i=S;i<=T;i++)dis[i]=inf; dis[S]=0; q.push(S); vis[S]=1; inc[S]=inf;//inc!! while(q.size()) { int x=q.front(); q.pop(); vis[x]=0; for(int i=hd[x],u;i;i=nxt[i]) if(dis[u=to[i]]>dis[x]+w[i]&&c[i]) { dis[u]=dis[x]+w[i]; pre[u]=i; inc[u]=Min(inc[x],c[i]); if(!vis[u])vis[u]=1,q.push(u); } } return dis[T]!=inf; } void up() { int x=T; while(x!=S) { int i=pre[x]; c[i]-=inc[T]; c[i^1]+=inc[T]; x=to[i^1]; } } int main() { m=rd(); n=rd(); S=0; T=id(n,0)+1; for(int j=1;j<=n;j++) for(int i=1,x;i<=m;i++) { x=rd(); for(int k=1;k<=n;k++) add(id(j,0),id(i,k),k*x,1); } for(int j=1;j<=n;j++)add(S,id(j,0),0,1); for(int i=id(1,1);i<=id(m,n);i++)add(i,T,0,1); int ans=0; while(bfs())ans+=dis[T]*inc[T],up(); printf("%.2f\n",1.0*ans/n); return 0; }