CCF-CSP-201403-4 无线网络 (100分)
题目:
试题编号: | 2014-03-4 |
---|---|
试题名称: | 无线网络 |
时间限制: | 1.0s |
内存限制: | 256.0M |
问题描述: | 目前在一个很大的平面房间里有 n 个无线路由器,每个无线路由器都固定在某个点上。 任何两个无线路由器只要距离不超过 r 就能互相建立网络连接。 除此以外,另有 m 个可以摆放无线路由器的位置。你可以在这些位置中选择至多 k 个增设 的路由器。 你的目标是使得第 1 个路由器和第 2 个路由器之间的网络连接经过尽量少的中转路由器。请问在最优方案下中转路由器的最少个数是多少?输入格式第一行包含四个正整数 n,m,k,r。(2 ≤ n ≤ 100,1 ≤ k ≤ m ≤ 100, 1 ≤ r ≤ 108)。 接下来 n 行,每行包含两个整数 xi 和 yi,表示一个已经放置好的无线 路由器在 (xi, yi) 点处。 输入数据保证第 1 和第 2 个路由器在仅有这 n 个路由器的情况下已经可以互相连接(经过一系列的中转路由器)。 接下来 m 行,每行包含两个整数 xi 和 yi,表示 (xi, yi) 点处可以增设 一个路由器。输入中所有的坐标的绝对值不超过 108,保证输入中的坐标各不相同。输出格式输出只有一个数,即在指定的位置中增设 k 个路由器后,从第 1 个路 由器到第 2 个路由器最少经过的中转路由器的个数。 样例输入 5 3 1 3 0 0 5 5 0 3 0 5 3 5 3 3 4 4 3 0 样例输出 2 |
解题思路:
- 这道题目的基础是通过节点之间的距离判断节点之间是否连通然后求出两个节点之间所需经过的最小中转次数.
- 但换个角度可以被看作是是图论当中的求两节点之间最短路径的问题,等同于在每对直接连通的节点之间的路径长度为1的情况下(这样求出最短路径就等同于求出最小中转次数),求出两节点之间最短路径的问题。这种问题可以采用Dijkastra,Spfa,Floyd等算法,但由于路径长度都被看作为1,因此使用bfs算法比较方便。
- 在使用bfs算法的情况下,如何解决确保在N+M的节点之中所选的额外节点数量不超过K个?我们需要用结构体定义每个节点,结构体之中需要设置一个k值来 代表 当遍历到当前节点时所选的额外节点的数目,通过这个数目的大小来判断下一步应该在什么范围的节点内遍历。
满分代码:
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 205;
long long n, m, k, r, max1=-1;
bool visit[maxn] = {};//默认值为false,确保刚开始每个节点都没有被走过
struct node {
long long x, y, k;
int step;
node () { step = k = 0; }//默认k=0
node (int x1, int y1, int s1, int k1) {x=x1;y=y1;step=s1;k=k1;}//有参构造函数
} map[maxn];//用来记录每个节点的信息
int bfs(int begin, int end)//利用深度优先算法遍历来计算起点到终点
{
queue<node> Q;
Q.push(node(map[begin].x, map[begin].y, 0, 0));//起始点入站
visit[begin] = true;//true说明该节点已经走过来,避免重复节点
while (!Q.empty())
{
node s = Q.front();
Q.pop();//入栈
if (s.x == map[end].x && s.y == map[end].y) return s.step - 1;//求出中转个数
if (s.k == k) max1=n; // 当前k值一旦到达k时只能在n里面走,不能用map[n]之外的节点了
else max1=n+m;//当前k值小于原k时就可以在map[n+m]里面走
for (int i=1;i<= max1;++i)
{
if (visit[i]) continue;//已经走过就不走了
if ((map[i].x - s.x)*(map[i].x - s.x) + (map[i].y - s.y)*(map[i].y - s.y) > r*r) continue;//距离不够就不走
visit[i] = true; //距离够了就开始准备走
int kk;
if(i>n)kk=s.k+1;
else kk=s.k;//根据当前节点的类型决定是否加k值
Q.push(node(map[i].x, map[i].y, s.step + 1, kk));//走进去,放进队列中
}
}
}
int main()
{
cin >> n >> m >> k >> r;
for (int i = 1; i <= n + m; ++i)
{
cin >> map[i].x >> map[i].y;
}//初始化输入
cout << bfs(1, 2);//输入结果
}