CSP201403-4 无线网络
题目链接:CSP201403-4
解题思路
首先考虑这m个位置都可以放路由器,没有k的限制。如果两个路由器的距离不超过r就可以建立连接,则该问题就成了一个图中求两点之间的距离的问题,图中所有边的权重为1。从源点开始BFS,第一次碰到终点得到的距离就是两者之间的最短距离。
加上k的限制后,路由器被分为两部分,一部分是前n个没有数量限制的,另一部分是后m个有数量限制的。在BFS的过程中对于遍历的每一个点多记录一下遍历到这个点的时候已经使用了多少个第二部分的路由器,如果已经等于k则在枚举邻接点的时候只枚举前n个即可。
点的数量比较小,可以用邻接矩阵来存储,时间复杂度𝑂𝑂( 𝑛𝑛 + 𝑚𝑚 2)。
这里全部采用数组的形式实现。在点中存储的信息除了点的坐标以外还包括到当前点为止浏览了m的点的数量和浏览了所有的点的数量,以及点的序号。点的序号对应了输入时点的下标,通过点的序号我们可以方便的找到点的所有信息。
代码
#include <stdio.h>
#include <string.h>
#include <queue>
#include <iostream>
#include <cmath>
using namespace std;
bool matrix[202][202];//为1表示邻接
struct node {
int x, y;
int order;//点序号
int count;//到当前点为止,已经遍历了m中的点的个数
int total;//到当前点为止,遍历的点的个数
}nn[202];
int n, m, k, r;
queue<struct node>q;
bool vis[202];
bool distance(int x1, int y1, int x2, int y2) {
return sqrt(pow(x1 - x2,2) + pow(y1 - y2,2)) <= r;
}
int bfs(int sindex,int dindex) {
q.push(nn[sindex]);
vis[0] = true;//标记已读
while (!q.empty()) {
struct node now = q.front(); q.pop();
int index = now.order;
if (index==dindex)
return now.total-1;
int j;
for (j = 0; j < n + m; j++) {
if (matrix[index][j] && !vis[j]) {
//找到邻接点
if (j >= n && now.count > k) {
break;
}
else {
struct node tmp = nn[j];
j >= n ? tmp.count = now.count + 1 : tmp.count = now.count;
tmp.total = now.total + 1;
vis[j] = true;
q.push(tmp);
}
}
}
}
}
int main(void) {
cin >> n >> m >> k >> r;
for (int i = 0; i < n + m; i++) {
cin >> nn[i].x >> nn[i].y;
nn[i].order = i; nn[i].count = 0; nn[i].total = 0;
}
for (int i = 0; i < n + m; i++) {
for (int j = 0; j < n + m; j++) {
if (i == j || !distance(nn[i].x, nn[i].y, nn[j].x, nn[j].y))
matrix[i][j] = false;
else
matrix[i][j] = true;
}
}
cout << bfs(0,1);
}
注意
在测试过程中发现得分总是60分,仔细检查代码发现没有逻辑上的问题,猜测发生了数据的溢出,而在这里容易出现数据溢出的就是求距离的函数。之前的写法写成
return sqrt((long long)(x1-x2)*(x1-x2)+(long long)(y1-y2)*(y1-y2));
然后再将返回的long long数和r做比较。
讲真我也不知道这种写法的问题出现在哪里(不过编译器确实有报出溢出的warning),后来改为直接调用pow函数成功100分。