题目大意:有m个人在河的南岸,他们要想到河的北岸。河宽w,每个人每秒可以跳一次,最多跳的距离为D。河中有n个石头,给你石头的坐标(x,y)。每个石头在同一时间最多载人为c。求,m个人都能到南岸的最短时间。
所有人都能到对岸的话,时间不会超过n+m。若D>=W,答案为1。否则,我们按时间拆点。在第一秒的时候,我们把0秒的石头连向汇点,源点连向1秒的石头,0秒的石头连向1秒的石头。注意,这里的连向,是一秒能到的(距离不超过D)。这个时候,跑最大流,若>=m,则说明1秒的时候,m个人都能到对岸。则否,在原图的基础上加边。2秒的时候。我们把1秒的石头连向汇点,源点连向2秒的石头,1秒的石头连向2秒的石头。在第i秒的时候,我们把i-1秒的石头连向汇点,源点连向i秒的石头,i-1秒的石头连向i秒的石头。这里需要注意的是,每秒的石头,仍然需要拆点。限制一个石头的出入边是没有用的。为什么呢?因为,假设一个石头的有多条入边,多条出边。如果你只是限制出入边的话,流经这个石头总的流量也许是超过限制的。实际上,我们每秒的石头都拆点后,其他边可以把容量设为INF就可以了。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
//typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=1000111222;
const double INFF=1e200;
const double eps=1e-8;
const int mod=1000000007;
const int NN=55;
const int MM=4010;
/* ****************** */
struct G
{
int v,cap,next;
}E[NN*NN*200],E1[NN*NN*2];
int p[NN*200],T,p1[NN],T1;
int x[NN],y[NN],c[NN];
int temp_p[NN*200],dd[NN*200],qw[NN*200];
void add1(int u,int v)
{
E1[T1].v=v;
E1[T1].next=p1[u];
p1[u]=T1++;
}
void add(int u,int v,int cap)
{
// printf("%d->%d:%d\n",u,v,cap);
E[T].v=v;
E[T].cap=cap;
E[T].next=p[u];
p[u]=T++;
E[T].v=u;
E[T].cap=0;
E[T].next=p[v];
p[v]=T++;
}
bool find_path(int st,int en,int n)
{
int i,u,v,head,tail;
for(i=0;i<=n;i++)
dd[i]=-1;
dd[st]=0;
qw[head=tail=0]=st;
while(head<=tail)
{
u=qw[head++];
for(i=p[u];i+1;i=E[i].next)
{
v=E[i].v;
if(dd[v]==-1 && E[i].cap>0)
{
dd[v]=dd[u]+1;
qw[++tail]=v;
}
}
}
return (dd[en]!=-1);
}
int dfs_flow(int u,int& en,int f)
{
if(u==en || f==0)
return f;
int temp,flow=0;
for( ; temp_p[u]+1 ; temp_p[u] = E[ temp_p[u] ].next)
{
G& e=E[temp_p[u]];
if(dd[e.v]==dd[u]+1)
{
temp=dfs_flow(e.v,en,min(f,e.cap));
if(temp>0)
{
f-=temp;
flow+=temp;
e.cap-=temp;
E[temp_p[u]^1].cap+=temp;
if(f==0)
break;
}
}
}
return flow;
}
int dinic(int st,int en,int n)
{
int i,ans=0;
while( find_path(st,en,n) )
{
for(i=0;i<=n;i++)
temp_p[i]=p[i];
ans+=dfs_flow(st,en,INF);
}
return ans;
}
void solve(int n,int sum)
{
memset(p,-1,sizeof(p));
T=0;
int i,j,k,v,ans=0;
for(i=1;i<=n+sum;i++)
{
for(j=p1[0];j+1;j=E1[j].next)
{
v=E1[j].v;
add(0,v+i*n*2,INF);
}
for(k=2;k<=n+1;k++)
{
for(j=p1[k];j+1;j=E1[j].next)
{
v=E1[j].v;
if(v==1)
add(k+i*n*2-n,1,INF);
else
add(k+i*n*2-n,v+i*n*2,INF);
}
add(k+i*n*2-n-n,k+i*n*2-n,c[k-1]);
}
k=dinic(0,1,i*n*2+n+1);
ans+=k;
// printf("max f==%d\n",k);
if(ans>=sum)
break;
}
if(i>n+sum)
puts("IMPOSSIBLE");
else
printf("%d\n",i);
}
int main()
{
int N,M,D,W;
int i,j;
while(scanf("%d%d%d%d",&N,&M,&D,&W)!=EOF)
{
memset(p1,-1,sizeof(p1));
T1=0;
for(i=1;i<=N;i++)
scanf("%d%d%d",&x[i],&y[i],&c[i]);
if(D>=W)
{
puts("1");
continue;
}
for(i=1;i<=N;i++)
{
if(y[i]<=D)
{
// add1(i+1,0);
add1(0,i+1);
}
if(W-y[i]<=D)
{
add1(i+1,1);
add1(1,i+1);
}
add1(i+1,i+1);
for(j=i+1;j<=N;j++)
{
if( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) <=D*D )
{
add1(i+1,j+1);
add1(j+1,i+1);
}
}
}
c[0]=INF;
solve(N,M);
}
return 0;
}