题目大意
一条宽为W的河。由y=0和y=W两条边界组成。
一些二维点,还有一些圆。每个圆都有半径和使用一次的代价。
你可以在每个二维点上放置一个圆或不放置,代价为该圆使用代价。
现在从y=0走到y=W,两个圆相交或相切则互相联通,与y=0相交或相切的圆可以通过,y=W同理。
求最小代价。
最短路
设(i,j)表示在第i个圆上放第j种圆,用一个点表示它。
对于(i,j)和(k,l),如果
r[j]+r[l]>=(xi−xj)2+(yi−yj)2−−−−−−−−−−−−−−−−−√
,那么(i,j)向(k,l)连c[l]的单向边。
建立源点S和汇点T,S对那些可以联通y=0的点连边,可以联通y=W的点向T连边,求S到T的最短路即可。
优化连边
点的数量是减不了了,考虑优化连边。
首先如果存在一个圆半径为x费用为a,另一个圆半径为y费用为b,如果满足x>=y但a<=b,那么(y,b)这个圆无意义。
于是按照r排序,c也是单调的。
对于一个(i,j)向k的m个点连边,找到最小的l可以让i与k联通,那么(i,j)向(k,l)连c[l]的单向边。
对于一个点i,(i,j-1)向(i,j)连c[j]-c[j-1]
易知原图的等价性没有改变!
新图是n^3的边数,跑最短路即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef double db;
const int mx=250+10,mx2=mx*mx,mx3=mx*mx*mx,inf=500000000;
struct dong{
int x,id;
friend bool operator <(dong a,dong b){
return a.x<b.x||a.x==b.x&&a.id<b.id;
}
} zlt;
multiset<dong> heap;
int f[mx2],h[mx2],go[mx3],next[mx3],dis[mx3],b[mx][mx],tance[mx][mx];
int x[mx],y[mx],r[mx],c[mx],id[mx],p[mx];
bool bz[mx2];
int i,j,k,l,now,s,t,n,m,w,ca,tot,top;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp(int x,int y){
return r[x]<r[y]||r[x]==r[y]&&c[x]>c[y];
}
db sqr(db x){
return x*x;
}
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=z;
next[tot]=h[x];
h[x]=tot;
}
int main(){
freopen("river.in","r",stdin);freopen("river.out","w",stdout);
ca=read();
while (ca--){
n=read();m=read();w=read();
tot=0;
fo(i,1,n) x[i]=read(),y[i]=read();
fo(i,1,n)
fo(j,1,n)
tance[i][j]=ceil(sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j])));
fo(i,1,m) r[i]=read(),c[i]=read(),id[i]=i;
sort(id+1,id+m+1,cmp);
fo(i,1,m) p[i]=r[id[i]];
fo(i,1,m) r[i]=p[i];
fo(i,1,m) p[i]=c[id[i]];
fo(i,1,m) c[i]=p[i];
l=inf;
top=0;
fd(i,m,1){
if (c[i]<l){
id[++top]=i;
l=c[i];
}
}
fo(i,1,top/2) swap(id[i],id[top-i+1]);
m=top;
fo(i,1,m) p[i]=r[id[i]];
fo(i,1,m) r[i]=p[i];
fo(i,1,m) p[i]=c[id[i]];
fo(i,1,m) c[i]=p[i];
top=0;
s=++top;
fo(i,1,n)
fo(j,1,m)
b[i][j]=++top;
t=++top;
fo(i,1,top) h[i]=0;
fo(i,1,n)
fo(k,1,n){
fo(j,1,m){
if (r[m]+r[j]<tance[i][k]) continue;
l=lower_bound(r+1,r+m+1,tance[i][k]-r[j])-r;
add(b[i][j],b[k][l],c[l]);
}
}
fo(i,1,n)
fo(j,2,m)
add(b[i][j-1],b[i][j],c[j]-c[j-1]);
fo(i,1,n)
fo(j,1,m)
if (r[j]>=y[i]) add(s,b[i][j],c[j]);
fo(i,1,n)
fo(j,1,m)
if (y[i]+r[j]>=w) add(b[i][j],t,0);
fo(i,1,top) f[i]=inf,bz[i]=0;
f[s]=0;
heap.clear();
fo(i,1,top){
zlt.x=f[i];zlt.id=i;
heap.insert(zlt);
}
while (!heap.empty()){
zlt=*heap.begin();
heap.erase(heap.begin());
k=zlt.id;
bz[k]=1;
now=h[k];
while (now){
if (!bz[go[now]]&&f[k]+dis[now]<f[go[now]]){
zlt.x=f[go[now]];zlt.id=go[now];
heap.erase(heap.find(zlt));
zlt.x=f[go[now]]=f[k]+dis[now];
heap.insert(zlt);
}
now=next[now];
}
}
if (f[t]==inf) printf("impossible\n");else printf("%d\n",f[t]);
}
}