P3344 [ZJOI2015] 幻想乡 Wi-Fi 搭建计划
首先有一个结论:如果所有圆都在上面(或下面),把点按照 \(x\) 坐标排序后,一定有一种最优方案使得每个圆只覆盖一段连续的区间。
画几个图,感性理解一下,会发现如果有更优的,那么两个圆的半径就不一样了,严谨证明我不会。
先按照 \(x\) 坐标排序,用 \(DP\)。设 \(f_{i,j,k}\) 表示把前 \(i\) 个点都覆盖了,上面用了前 \(j\) 个圆中的一些,下面用了前 \(j\) 个圆中的一些的最小代价。
为了方便,可以强制 \(f_{i,j,k}\) 中上面第 \(j\) 个和下面第 \(k\) 个事必选的。
转移的时候就枚举下一个圆,如果可以覆盖到 \(i\) 就可以转移,注意:如果新的圆就是上面的第 \(j\) 个或下面的第 \(k\) 个是没有代价的,因为祂们都已经付过了。
代码
/*
Luogu P3344 [ZJOI2015] 幻想乡 Wi-Fi 搭建计划
2026-03-25
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL long long
const int maxn=110,inf=1000000000;
int n,m,R,f[maxn][maxn][maxn],cnt_up,cnt_dn;
struct Point{int x,y,w;}a[maxn],rl[maxn],cr[maxn],cr_up[maxn],cr_dn[maxn];
bool check(Point u,Point v){
LL dis=1ll*(u.x-v.x)*(u.x-v.x)+1ll*(u.y-v.y)*(u.y-v.y);
if(dis<=1ll*R*R) return 1;
return 0;
}
signed main(){
read(n,m,R);
for(int i=1;i<=n;i++) read(a[i].x,a[i].y);
cr_dn[0]=cr_up[0]={inf,inf};
for(int i=1;i<=m;i++){
read(cr[i].x,cr[i].y,cr[i].w);
if(cr[i].y<0) cr_dn[++cnt_dn]=cr[i];
else cr_up[++cnt_up]=cr[i];
}
sort(cr_dn+1,cr_dn+cnt_dn+1,[](Point a,Point b){return a.x<b.x;});
sort(cr_up+1,cr_up+cnt_up+1,[](Point a,Point b){return a.x<b.x;});
int cnt=0;
for(int i=1;i<=n;i++){
bool can=0;
for(int j=1;j<=m;j++) if(check(cr[j],a[i])){can=1;break;}
if(can) rl[++cnt]=a[i];
}
n=cnt,swap(a,rl);
sort(a+1,a+1+n,[](Point a,Point b){return a.x<b.x;});
write(n),write("\n");
memset(f,0x3f,sizeof(f));
f[0][0][0]=0;
for(int i=1;i<=n;i++) for(int j=0;j<=cnt_up;j++) for(int k=0;k<=cnt_dn;k++){
if(check(cr_up[j],a[i])||check(cr_dn[k],a[i])) f[i][j][k]=min(f[i][j][k],f[i-1][j][k]);
for(int l=j+1;l<=cnt_up;l++) if(check(cr_up[l],a[i])) f[i][l][k]=min(f[i][l][k],f[i-1][j][k]+cr_up[l].w);
for(int l=k+1;l<=cnt_dn;l++) if(check(cr_dn[l],a[i]))f[i][j][l]=min(f[i][j][l],f[i-1][j][k]+cr_dn[l].w);
}
int ans=inf;
for(int i=0;i<=cnt_up;i++) for(int j=0;j<=cnt_dn;j++) ans=min(ans,f[n][i][j]);
write(ans);
return 0;
}

浙公网安备 33010602011771号