bzoj 1070 [SCOI2007]修车——网络流(拆边)

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

后面还有几辆车在这个人这儿修,自己这辆车的时间对总时间的贡献就要多乘上几倍。

所以可以费用流。每辆车向每个人连 n 条边,费用依次为 d , 2*d , 3*d …… 表示自己后面有几辆车。

对于一个人来说,还要限制走 k*d 这条边的一共只能有一辆车。只需要将一个人拆成 n 个点,每个点向汇点连容量为1的边就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
const int N=605,M=66005,INF=65;
int n,m,t,hd[N],xnt=1,cur[N],to[M],nxt[M],cap[M],w[M];
int dis[N],pre[N],info[N],ans; bool ins[N];
queue<int> q;
void add(int x,int y,int z)
{
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=1;w[xnt]=z;
  to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;w[xnt]=-z;
}
bool spfa()
{
  memset(dis,0x3f,sizeof dis);dis[0]=0;
  info[0]=INF;info[t]=0;
  q.push(0);ins[0]=1;
  while(q.size())
    {
      int k=q.front();q.pop();ins[k]=0;
      for(int i=hd[k],v;i;i=nxt[i])
    if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
      {
        dis[v]=dis[k]+w[i];
        pre[v]=i; info[v]=Mn(info[k],cap[i]);
        if(!ins[v])q.push(v),ins[v]=1;
      }
    }
  return info[t];
}
void ek()
{
  int s=info[t];
  for(int i=pre[t];i;i=pre[to[i^1]])
    {
      ans+=s*w[i];cap[i]-=s;cap[i^1]+=s;
    }
}
int main()
{
  scanf("%d%d",&m,&n);int ct=n*m; t=ct+n+1;
  for(int i=1,x=ct+1,d;i<=n;i++,x++)
    for(int j=1,y=1;j<=m;j++,y++)
      {
    d=rdn();
    for(int k=1,lj=d;k<=n;k++,lj+=d,y++)
      add(x,y,lj);
      }
  for(int i=1,x=ct+1;i<=n;i++,x++)add(0,x,0);
  for(int i=1;i<=ct;i++)add(i,t,0);
  while(spfa())ek();
  printf("%.2f\n",(double)ans/n);
  return 0;
}

 

posted on 2018-12-21 16:42  Narh  阅读(232)  评论(0编辑  收藏  举报

导航