题意模拟
第一个路由器(0,0)和第二个路由器(5,5)经过若干个中转路由器已经相连(黄色路径):
现在又增添了m个位置,可以在这m个位置中的任一个位置放一个路由器,使得从第一台路由器到达第二台路由器的距离最短:
我们发现不论怎么走,从第一个路由器走到第二个路由器,都要经过两个中转路由器,因此最短路径就是2:
OK,很明显,这道题是一个bfs求最短路径题。
code
1.刚开始给n个点,我们把这n个点放到p数组。然后又给m个特殊点,我们也把这m个特殊点放到p数组里。
2.遍历p数组,如果两个节点的距离小于等于r,那么就在两个点之前建一条边。
3.关系建立后用bfs()寻求最短路。因为题目求的是最少的中转路由器个数,因此我们无需关注路径长度,把节点个数当做长度计算即可。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int>PII;
#define x first
#define y second
typedef long long LL;
int n, m,k,r;
const int N = 210, M = N * N;
PII p[N]; //存特殊点
int h[N]; //头节点
int ne[M]; //指向下一个节点的指针
int e[M]; //边值
int dist[N][N]; //距离数组
int idx; //地址
void add(int a, int b)
{
e[idx] = b; //把b赋值给边值
ne[idx] = h[a]; //头节点指向下一个节点
h[a] = idx++; //头节点移到下一个节点
}
//求最短路
int bfs()
{
queue<PII> q;
q.push({ 1,0 }); //1号点加入队列
memset(dist,0x3f,sizeof dist);
dist[1][0] = 0; //1号点到1号店的距离为1
while(q.size())
{
PII t = q.front();
q.pop();
for (int i = h[t.x]; i != -1; i = ne[i]) //头节点走到空为止
{
int x = e[i], y = t.y; //x表示节点编号,y表示走过的特殊点的·个数
if (x > n) y++; //x>n,说明是特殊点,走过的特殊点的个数++
if (y <= k) //不能超过k个点
{
if (dist[x][y] > dist[t.x][t.y] + 1)
{
dist[x][y] = dist[t.x][t.y] + 1;
q.push({ x,y });
}
}
}
}
//求一下最小值
int res = 1e8;
for (int i=0;i<=k;i++)
{
res = min(res,dist[2][i]);
}
return res - 1; //求1~n之间的点的最小个数,不包含1和n这两个点
}
bool check(PII a,PII b)
{
LL dx = a.x - b.x;
LL dy = a.y - b.y;
return dx * dx + dy * dy <= (LL)r * r;
}
int main()
{
cin >> n >> m >>k>> r;
memset(h,-1,sizeof h);
for (int i = 1; i <= n; i++)cin >> p[i].x >> p[i].y;
for (int i = n + 1; i <= n + m; i++)cin >> p[i].x >> p[i].y;
//如果距离小于r,就可以建边
for (int i = 1; i <= n + m; i++)
{
for (int j = i + 1; j <= n + m; j++)
{
if (check(p[i],p[j]))
{
add(i,j), add(j,i);
}
}
}
cout << bfs();
return 0;
}