第一次CCF计算机能力软件认证D题 -无限网络 题型:图论,最短路

87 阅读2分钟

3200. 无线网络 - AcWing题库

题意模拟

第一个路由器(0,0)和第二个路由器(5,5)经过若干个中转路由器已经相连(黄色路径):

image.png

现在又增添了m个位置,可以在这m个位置中的任一个位置放一个路由器,使得从第一台路由器到达第二台路由器的距离最短:

image.png

我们发现不论怎么走,从第一个路由器走到第二个路由器,都要经过两个中转路由器,因此最短路径就是2: image.png

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;
}

image.png