题目: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 ",1.0*ans/n); return 0; }