题目大意
解题思路
删掉半径小费用大的盘,盘就变成半径费用单调。以第i个柱,j种盘为点,枚举另一个点,利用单调性找出最小相交的盘子连边,每个柱小盘子向大盘子连边,边权为差值,再跑最短路就可以了。
code
using namespace std;
int const maxn=250;
int T,n,m,w,gra,x[maxn+10],y[maxn+10],r[maxn+10],c[maxn+10],
inq[maxn*maxn+10],q1[maxn*maxn*10+10],begin[maxn*maxn+10],to[maxn*maxn*maxn+10],
len[maxn*maxn*maxn+10],next[maxn*maxn*maxn+10];
double dis[maxn+10][maxn+10];
long long f[maxn*maxn+10],inf=1e18;
void insert(int u,int v,int w){
to[++gra]=v;
len[gra]=w;
next[gra]=begin[u];
begin[u]=gra;
}
int main(){
//freopen("river.in","r",stdin);
//freopen("river.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d",&T);
fo(cas,1,T){
scanf("%d%d%d",&n,&m,&w);int ok=1;
fo(i,1,n)scanf("%d%d",&x[i],&y[i]);
fo(i,1,n)fo(j,1,n)dis[i][j]=sqrt(1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]));
fo(i,1,m)scanf("%d%d",&r[i],&c[i]);
fo(i,1,m-1)
fo(j,i+1,m){
if((r[j]>r[i])||((r[j]==r[i])&&(c[j]<c[i]))){
swap(r[j],r[i]);
swap(c[j],c[i]);
}
}
int tmp=m,mi=c[1];
for(int i=2;i<=tmp;i++){
if(c[i]>=mi){
fo(j,i,tmp-1){
r[j]=r[j+1];
c[j]=c[j+1];
}
tmp--;
}else mi=min(mi,c[i]);
}
m=tmp;
fo(i,1,m-1)
fo(j,i+1,m){
if(r[j]<r[i]){
swap(r[j],r[i]);
swap(c[j],c[i]);
}
}
int he=0,ti=0;
fo(i,1,n)fo(j,1,m)f[num(i,j)]=inf,inq[num(i,j)]=0;
fo(i,1,n)fo(j,1,m)
if(y[i]-r[j]<=0){
inq[q1[++ti]=num(i,j)]=1;
f[num(i,j)]=min(f[num(i,j)],c[j]);
}
gra=0;fo(i,1,n*m)begin[i]=0;int l;
fo(i,1,n)fo(k,1,n)if(i!=k){
l=m;
fo(j,1,m){
while((l>1)&&(dis[i][k]-1e-10<=r[j]+r[l-1]))l--;
if(dis[i][k]-1e-10<=r[j]+r[l])insert(num(i,j),num(k,l),c[l]);
}
}
fo(i,1,n)fo(j,1,m-1)insert(num(i,j),num(i,j+1),c[j+1]-c[j]);
for(;he!=ti;){
he++;
for(int i=begin[q1[he]];i;i=next[i])
if(f[q1[he]]+len[i]<f[to[i]]){
f[to[i]]=f[q1[he]]+len[i];
if(!inq[to[i]])inq[q1[++ti]=to[i]]=1;
}
inq[q1[he]]=0;
}
long long ans=inf;
fo(i,1,n)fo(j,1,m)
if(y[i]+r[j]>=w)
ans=min(ans,f[num(i,j)]);
if(ans!=inf)printf("%lld\n",ans);
else printf("impossible\n");
}
return 0;
}