438. The Glorious Karlutka River =)
Memory limit: 262144 kilobytes
output: standard
A group of M tourist s are walking along the Karlutka river. They want to cross the river, but they couldn't find a bridge. Fortunately, there are some piles of rubbish floating in the water, and the tourist s have decided to try to cross the river by jumping from one pile to another.
A tourist can move up to D meters in any direction at one jump. One jump takes exactly one second. tourist s know that the river is W meters wide, and they have estimated the coordinates of rubbish piles ( X i , Y i ) and the capacity of each pile ( C i , the maximum number of tourist s that this pile can hold at the same time). Rubbish piles are not very large and can be represented as points. The river flows along the X axis. tourist s start on the river bank at 0 by Y axis. The Y coordinate of the opposite bank is W .
tourist s would like to know if they can get to the opposite bank of the river, and how long it will take.
sample input | sample output |
3 10 3 7 0 2 2 4 2 2 2 4 3 | 6 |
sample input | sample output |
3 10 3 8 0 2 2 4 2 2 2 4 3 | IMPOSSIBLE |
题意:有一条河,河上有一些垃圾(看成点),人借助垃圾跳到对岸,已知垃圾坐标位置,人每次最大跳跃距离,河的宽度以及人数,问是否所有人可以跳到对岸,若可以,求出最短时间。
这题需要求时间,显然是个动态建模问题,与家园一题的大致思想类似。传送门:家园
但是难度比家园稍大,很显然要暴力枚举时间,知道所有人都跳过为止。我们知道时间的上限是n+m,因为对于第一个人他从一河岸跳到对岸最多踩m个垃圾,加上到达对岸的一步,共需花m+1单位的时间,而第二个人他可以在第一人跳到第二个垃圾时重复第一人的跳法,也就是后面一人比前面一人晚到对岸1个单位时间,那么有n-1人重复此过程,因此最大时间m+1+n-1=m+n,若超过此时间,所有人未到对岸,显然是无解情况。
对于有解情况:我们先预处理所有垃圾两两之间的距离是否小于等于D,也就是能否在这些垃圾之间跳来跳去,
麻烦的是河岸并不是一个点,而是一条线,因此我们也要预处理能从左岸(出发地)跳到的垃圾(y坐标<=D),和能从哪些垃圾跳到对岸(y坐标+D>=M).
然后根据时间拆点,记i点在t时刻的状态为(i,t),这里注意t=1,就是直接从左岸跳到对岸,这个可以判断D>=M求得,然后我们从t=2开始枚举,这里要考虑清楚,我之前建模没想明白,t-1时刻,人是站在(i,t-1)状态上的,那么t时刻人可以从(i,t-1)跳到对岸(如果满足条件的话),也就是要将所有(i,t-1)连向汇点,
千万不要将(i,t)连向汇点,当然也可以选择从(i,t-1)跳到(j,t)(i,j距离<=D),当然不要忘了从左岸连向那些y坐标<=D的点(一步可达点),这样就差不多了。
最后别忘了,每个点需要拆成两个点,不这样做的话会有大量流量聚集在i点,然后通过下一时刻流出去,这样就超过i在某一时刻最大人数限制了。此题拆点是挺麻烦的。
PS:这里最多会有10000割点左右,最坏情况有10^8条边,显然内存不允许,dinic算法也会TLE,所以可以推断,数据显然不会出现这么多边和点的情况。所以随便开了2000000就AC。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define eps 1e-6
#define Maxn 15000
using namespace std;
const int step=6500;
const int mstep=60;
double x[60],y[60];
int num[60],dist[60][60],ck1[60],ck2[60];
bool dis(int i,int j,double D){
double dt=(x[i]-x[j])*(x[i]-x[j])+
(y[i]-y[j])*(y[i]-y[j]);
return dt<D*D||fabs(dt-D*D)<eps;
}
const int inf=0x3f3f3f3f;
struct line{
int to,next,cap;
}p[2000000];
int head[Maxn];
int q[Maxn];
int d[Maxn];
int tot;
int src,t;
int n,m;
void addedge(int a,int b,int c){
p[tot].to=b;
p[tot].next=head[a];
p[tot].cap=c;
head[a]=tot++;
}
void insert(int a,int b,int c){
addedge(a,b,c);
addedge(b,a,0);
}
bool bfs(){
memset(d,-1,sizeof d);
int s=0,e=-1;
q[++e]=src;
d[src]=0;
while(s<=e){
int u=q[s++];
for(int i=head[u];i!=-1;i=p[i].next){
int v=p[i].to;
if(d[v]==-1&&p[i].cap){
d[v]=d[u]+1;
q[++e]=v;
}
}
}
return d[t]!=-1;
}
int dfs(int u,int alpha){
if(u==t) return alpha;
int w,used=0;
for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
int v=p[i].to;
if(p[i].cap&&d[v]==d[u]+1){
w=dfs(v,min(alpha-used,p[i].cap));
used+=w;
p[i].cap-=w;
p[i^1].cap+=w;
}
}
if(!used) d[u]=-1;
return used;
}
int dinic(int i){
int ans=0;
src=0,t=n+1+mstep*i;
while(bfs())
ans+=dfs(src,inf);
return ans;
}
int main()
{
int D,W;
while(cin>>n>>m>>D>>W){
for(int i=1;i<=n;i++)
cin>>x[i]>>y[i]>>num[i];
if(D>=W||fabs(D-W)<eps) {puts("1");continue;}
tot=0;
memset(head,-1,sizeof head);
memset(ck1,0,sizeof ck1);
memset(ck2,0,sizeof ck2);
for(int i=1;i<=n;i++){
if(y[i]<D||fabs(D-y[i])<eps) ck1[i]=1;
if(y[i]+D>W||fabs(y[i]+D-W)<eps) ck2[i]=1;
}
memset(dist,0,sizeof dist);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dis(i,j,D)) dist[i][j]=1;
for(int i=1;i<=n;i++) //初始化时刻1
if(ck1[i]){
insert(0,i+mstep,inf);
insert(i+mstep,i+mstep+step,num[i]);
}
int res=m,ans;
bool flag=false;
for(int i=2;i<=n+m;i++){
for(int j=1;j<=n;j++){
insert(j+i*mstep,j+i*mstep+step,num[j]); //拆点
if(ck1[j]) insert(0,j+i*mstep,inf); //源点连向此时刻
if(ck2[j]) insert(j+(i-1)*mstep+step,n+1+mstep*i,inf); //前一时刻连向汇点
}
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(dist[j][k]) insert(j+(i-1)*mstep+step,k+i*mstep,inf);
res-=dinic(i);
if(res<=0){
flag=true;
ans=i;
break;
}
}
if(flag) printf("%d\n",ans);
else puts("IMPOSSIBLE");
}
return 0;
}