題意:寬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;}