SGU 438 动态流

题意:宽W的河面上有N个垃圾堆,每个垃圾堆只能站C人。河对岸有M个人,他们想借着垃圾堆跳着过河,当然,如果河比较窄,可以直接跳过河。每个人跳跃一次最多可以跳D远,问那些人过河的最短时间。

做法:此题不可以用费用流做,因为,每个人完全可以中途站在垃圾堆上,然后再跳过去。所以用了动态流的方法,把图按照时间轴,分成一层一层的。这样就先枚举时间,然后用最大的手法做题。参考了大牛的做法,学了一些宏函数的定义。

#include<stdio.h>
#include<string.h>
#define eps 1e8
#define LMT 55
#define T(x,i) ((x)+(i-1)*50)//在每一个时间加入的不同点。
#define CH(x)  ((x)+5000)
#define tt 11274//一开始tt定义错误,陷入无限循环
typedef struct
{
    int x,y;
}node;
typedef struct
{
    int u,v,next,c;
}line;
node nod[LMT*205];
line e[(LMT*LMT+LMT)*205];
int next[LMT*205],cap[LMT],lev[LMT*205],q[LMT*205],l[LMT*205];
bool mat[LMT][LMT];
int all,n,m,d,w;
int test(int a,int b)
{
    return (nod[a].x-nod[b].x)*(nod[a].x-nod[b].x)+
     (nod[a].y-nod[b].y)*(nod[a].y-nod[b].y)<=d*d;
}
void insert(int u,int v,int c)
{
    e[all].u=u;
    e[all].v=v;
    e[all].c=c;
    e[all].next=next[u];
    next[u]=all++;
    e[all].u=v;
    e[all].v=u;
    e[all].c=0;
    e[all].next=next[v];
    next[v]=all++;
}
int bfs(int s,int t)
{
    int u,v,x,head,tail;
    memset(lev,0,sizeof(lev));
    head=tail=0;
    q[tail++]=s;lev[s]=1;
    while(head<tail)
    {
        u=q[head++];
        for(x=next[u];x!=-1;x=e[x].next)
        {
            v=e[x].v;
            if(lev[v]==0&&e[x].c>0)
            {
                lev[v]=lev[u]+1;
                q[tail++]=v;
            }
        }
    }
    return lev[t]!=0;
}
int dfs(int s,int t)
{
    int u,v,x,top=0,ret=0;
    q[top++]=s;
    while(top>0)
    {
        u=q[top-1];
        if(u==t)
        {
            int back,i,min=eps+10;
            for(i=1;i<top;i++)
            {
                x=l[q[i]];
             if(min>e[x].c)
              {
                x=l[q[i]];
                min=e[x].c;
                back=i;
               }
            }
            ret+=min;
            for(i=1;i<top;i++)
            {
                x=l[q[i]];
                e[x].c-=min;
                e[x^1].c+=min;
            }
            top=back;
        }
        else
        {
            for(x=next[u];x!=-1;x=e[x].next)
            {
                v=e[x].v;
                if(lev[v]==lev[u]+1&&e[x].c>0)
                {
                    q[top++]=v;
                    l[v]=x;
                    break;
                }
            }
            if(x==-1)
            {
                lev[u]=0;
                top--;
            }
        }
    }
    return ret;
}
int dinic(int s,int t)
{
    int ret=0;
    while(bfs(s,t))
      ret+=dfs(s,t);
    return ret;
}
int main()
{
    int i,j,k,get=0,s,t;
    scanf("%d%d%d%d",&n,&m,&d,&w);
    memset(mat,0,sizeof(mat));
    memset(next,-1,sizeof(next));
    all=0;
    s=0;t=tt;
    for(i=1;i<=n;i++)
    scanf("%d%d%d",&nod[i].x,&nod[i].y,&cap[i]);
    for(i=1;i<=n;i++)
      for(j=i+1;j<=n;j++)
      if(test(i,j))
        mat[i][j]=mat[j][i]=1;
      if(d>=w)
      {
          printf("1\n");
          return 0;
      }
      for(i=1;i<=n+m;i++)
      {
          for(j=1;j<=n;j++)
          {
              insert(T(j,i),CH(T(j,i)),cap[j]);
              if(nod[j].y-d<=0)
              insert(s,T(j,i),eps);
              if(nod[j].y+d>=w)
              insert(CH(T(j,i)),t,eps);
              for(k=1;k<=n;k++)
              if(mat[j][k])
                insert(CH(T(j,i)),T(k,i+1),eps);//跳一次需要一秒,所以i时刻的点只可与i+1时刻的相连。
          }
          get+=dinic(s,t);
          if(get>=m)break;
      }
      if(get<m)printf("IMPOSSIBLE\n");
      else printf("%d\n",i+1);
      return 0;
}

你可能感兴趣的:(SGU 438 动态流)