CCF CSP 无线网络 BFS

问题描述
  目前在一个很大的平面房间里有 n 个无线路由器,每个无线路由器都固定在某个点上。任何两个无线路由器只要距离不超过 r 就能互相建立网络连接。
  除此以外,另有 m 个可以摆放无线路由器的位置。你可以在这些位置中选择至多 k 个增设新的路由器。
  你的目标是使得第 1 个路由器和第 2 个路由器之间的网络连接经过尽量少的中转路由器。请问在最优方案下中转路由器的最少个数是多少?
输入格式
  第一行包含四个正整数 n,m,k,r。(2 ≤ n ≤ 100,1 ≤ k ≤ m ≤ 100,)。
  接下来 n 行,每行包含两个整数 x i 和 y i,表示一个已经放置好的无线 路由器在 (x i, y i) 点处。输入数据保证第 1 和第 2 个路由器在仅有这 n 个路由器的情况下已经可以互相连接(经过一系列的中转路由器)。
  接下来 m 行,每行包含两个整数 x i 和 y i,表示 (x i, y i) 点处可以增设 一个路由器。
  输入中所有的坐标的绝对值不超过 10 8,保证输入中的坐标各不相同。
输出格式
  输出只有一个数,即在指定的位置中增设 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、解题分析

要求找“最短”,每次都是从一个状态转移到另一个状态,可以使用广搜解决。需要确认BFS时各节点表示的状态是用哪几个参数表示。题目输入的坐标访问可以很大,所以需要离散化存储坐标,在vector中连续的存储输入的坐标,这样可以用数组的下标id去确定任意一个路由器。那么广搜树上每个节点所表示的状态就是由三个参数组成:id表示路由器的坐标,step表示到该状态时中转了多少个路由器,k_num表示到该状态时已经新设了多少个路由器。

2、坑点说明

只需要注意数据规模,1 ≤ r,x,y≤ 108,如果是int类型的数,因为int是32位的,所以最大可以表示到232,也就是4,294,967,296。对于表示108并没有问题,但是我的程序里需要比较两个路由器之间的距离需要对r、x、y做平方,那么就得用到最大可表示的long long类型存储了。我开始就是这里给扣了20分。

还有一个需要吐槽的,这题的测试数据,似乎对k没有做任何要求,我看有的程序不对k做设置都行。。。

代码如下:

#include<iostream>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define INF 1<<31
int n,m,k;
LL r;
struct node{
	LL x;
	LL y;
}N;
struct info{
	LL step;//经过了多少个路由器 
	LL k_num;//新设置了几个路由器 
	int id;//该节点的序号 
}T;
queue<struct info> q;
vector<struct node> vec;
bool get[220];
bool Judge(LL x1,LL y1,LL x2,LL y2)
{
	LL x = x1-x2;
	LL y = y1-y2;
//	cout << "x1=" << x1<<" y1="<<y1<<" x2="<<x2<<" y2="<<y2<< " x="endl;
	if( (x*x + y*y) <= r*r)
	{
		return true;
	}else{
		return false;
	}
}
int BFS()
{
	 struct info new_T;
	 int id;
	 LL num=INF;//置为最大值 
     T.step=0;
	 T.k_num=0;
	 T.id=0;
	 q.push(T);
	 get[0]=true;
	 while(!q.empty())
	 {
	 	new_T = q.front();
	 	q.pop();
	 	id = new_T.id;
	 	
	 	if(Judge(vec[id].x,vec[id].y,vec[1].x,vec[1].y))
		{
			/*if(new_T.step<num)
			{
				num = new_T.step; 
			}*/
			return new_T.step;
		}
	 	for(int i=0;i<vec.size();i++)
	 	{
	 		if(!get[i] && i!=id && Judge(vec[id].x,vec[id].y,vec[i].x,vec[i].y))
	 		{
	 		
	 			if(new_T.k_num==k && i>=n)//当前以及选中k个新设立的路由器,不能再加入新的路由器 
	 			{
	 				continue;
	 			}
	 			get[i]=true;
	 			T.step=new_T.step+1;
	 			if(i>=n)//说明是新设的路由器 
	 			{
				    T.k_num=new_T.k_num+1;	
	 			}else{
	 				T.k_num=new_T.k_num;
	 			}
	            T.id=i;
	            q.push(T);
	 		}
	 	}
	 }
	 return num;
}
int main()
{
	long long x,y; 
	cin >> n >> m >> k >> r;
	for(int i=0;i<n+m;i++)
	{
		cin >> N.x >> N.y;
		vec.push_back(N);
	}
	cout << BFS();
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值