CCF201403 无线网络【限制型最短路】

问题描述
  目前在一个很大的平面房间里有 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.首先建图,对于任意两个距离小于 r 的点连无向边。边权设为 1。当找到1与2的最短路,那么中转的点的数量就是dis[2] - 1。
2.因为是在m个点选择k个点增设。那么每次从队列中选择一个点进行松弛的时候,要判断 to 的编号是否大于 n ,以及目前已经选择了多少个点,不得超过k。
3.用vis[][]二维数组来记录状态,表示 i 点在已经选择增设了 k 个点的情况下 是否存在于队列中。
4.需要注意在比较距离是否小于r时,数据会爆int。要先转化成ll型或者直接开ll型的数组。
代码如下:
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<queue>
  4 #define mem(a, b) memset(a, b, sizeof(a))
  5 typedef long long ll;
  6 using namespace std;
  7 const int MAXN = 210;
  8 const int inf = 0x3f3f3f3f;
  9 
 10 int n, m, k;
 11 ll r; //n + m个点 其中 m 个点是可选择添入的 最后可增设其中 k 个点。 
 12 ll x[MAXN], y[MAXN];
 13 int head[MAXN], cnt, vis[MAXN][110], dis[MAXN];
 14 
 15 struct Edge
 16 {
 17     int to, next, w;
 18 }edge[MAXN * (MAXN - 1)];
 19 
 20 struct Node
 21 {
 22     int pot, num;
 23 }node;
 24 
 25 void add(int a, int b, int c)
 26 {
 27     cnt ++;
 28     edge[cnt].to = b;
 29     edge[cnt].w = c;
 30     edge[cnt].next = head[a];
 31     head[a] = cnt;
 32 }
 33 
 34 void spfa()
 35 {
 36     queue<Node> Q;
 37     node.pot = 1, node.num = 0;
 38     dis[1] = 0;
 39     vis[1][0] = 1;
 40     Q.push(node);
 41     while(!Q.empty())
 42     {
 43         Node a = Q.front();
 44         Q.pop();
 45         vis[a.pot][a.num] = 0;
 46         for(int i = head[a.pot]; i != -1; i = edge[i].next)
 47         {
 48             int to = edge[i].to;
 49             int p = a.num;
 50             if(to > n)
 51                 p ++;
 52             if(dis[to] > dis[a.pot] + edge[i].w && p <= k)
 53             {
 54                 dis[to] = dis[a.pot] + edge[i].w;
 55                 if(!vis[to][p])
 56                 {
 57                     vis[to][p] = 1;
 58                     node.pot = to, node.num = p;
 59                     Q.push(node);
 60                 }
 61             }
 62         }
 63     }
 64 }
 65 
 66 int main()
 67 {
 68     mem(head, -1), cnt = 0;
 69     mem(vis, 0), mem(dis, inf);
 70     scanf("%d%d%d%lld", &n, &m, &k, &r);
 71     for(int i = 1; i <= n + m; i ++)
 72         scanf("%lld%lld", &x[i], &y[i]);
 73     for(int i = 1; i < n + m; i ++)
 74     {
 75         for(int j = i + 1; j <= n + m; j ++)
 76         {
 77             if((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= r * r)
 78             {
 79                 add(i, j, 1);
 80                 add(j, i, 1);
 81             }
 82         }
 83     }
 84     spfa();
 85     printf("%d\n", dis[2] - 1);
 86     return 0;
 87 }
 88 
 89 /*
 90 测试数据:
 91 5 3 1 3
 92 0 0
 93 5 5
 94 0 3
 95 0 5
 96 3 5
 97 3 3
 98 4 4
 99 3 0
100 2
101 
102 10 1 1 2
103 0 0
104 3 1
105 -2 0
106 -2 2
107 -2 4
108 -2 6
109 0 6
110 2 6
111 2 4
112 2 2
113 2 0
114 1
115 
116 10 1 1 2
117 0 0
118 3 1
119 -2 0
120 -2 2
121 -2 4
122 -2 6
123 0 6
124 2 6
125 2 4
126 2 2
127 3 0
128 8
129 
130 6 3 2 50000000
131 0 0
132 50000000 100000000
133 100000000 100000000
134 100000000 0
135 100000000 50000000
136 50000000 0
137 -100000000 50000000
138 0 50000000
139 0 100000000
140 2
141 */
View Code

 

posted @ 2019-11-14 22:40  缘未到  阅读(190)  评论(0编辑  收藏  举报