题意:宽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; }