传送门:CCF201403-4 无线网络
若把距离小于等于r的两路由器视为存在一条边,则题目可以归为求无权无向图的最短路径,就变得十分简单了。
直接跑一遍spfa,求得点1到其他点的最短路。因为题目要求的是最少经过的中转路由器的数量,而我们用spfa求得的最短路是包含了终点的,故要输出点1到点2的最短路的值-1 (s)。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 256;
struct point
{
ll x, y;
}p[maxn];
struct node //后面的spfa需要用到的结构
{
int x, k; //x为路由器的编号,k为选取x后已增设的路由器数量
node() {}
node(int X, int K): x(X), k(K) {}
};
int n, m, k, dis[maxn], vis[maxn];
ll r, d[maxn][maxn];
void read()
{
cin >> n >> m >> k >> r;
for(int i = 1; i <= n+m; ++i)
cin >> p[i].x >> p[i].y;
r *= r;
//r的最大值为1e8,r^2为1e16,不会爆long long,直接用r^2,省去麻烦的开方操作
for(int i = 1; i < n+m; ++i)
for(int j = i+1; j <= n+m; ++j)
{
ll x1 = p[i].x, x2 = p[j].x;
ll y1 = p[i].y, y2 = p[j].y;
d[i][j] = d[j][i] = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
//其实可以开一个vector<int>数组,存相连的点
//在这里判断d[i][j]是否小于等于r,存进vector数组中
//后面spfa的for循环的范围就会小一些
//但由于m+n的数量级非常小,且博主很懒QAQ,就没有写了
}
}
void spfa()
{
for(int i = 2; i <= n+m; ++i)
dis[i] = INF;
dis[1] = 0;
queue <node> q;
q.push(node(1, 0));
while(!q.empty())
{
node cur = q.front();
q.pop();
vis[cur.x] = 0;
for(int i = 2; i <= n+m; ++i)
{
if(cur.k >= k && i > n) //当已增设的路由器数量等于k,就不能再增设了
break;
if(d[cur.x][i] <= r && dis[i] > dis[cur.x]+1) //每条边权值相当于1
{
dis[i] = dis[cur.x]+1;
if(!vis[i])
{
if(i > n)
q.push(node(i, cur.k+1)); //增设路由器
else
q.push(node(i, cur.k));
vis[i] = 1;
}
}
}
}
}
void solve()
{
spfa();
cout << dis[2]-1;
}
int main()
{
read();
solve();
return 0;
}