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;
}

 

posted @ 2018-12-21 12:12  Zinn  阅读(139)  评论(0编辑  收藏  举报