Day3
题目描述
目前在一个很大的平面房间里有 \(n\) 个无线路由器,每个无线路由器都固定在某个点上。
任何两个无线路由器只要距离不超过 \(r\) 就能互相建立网络连接。
除此以外,另有 \(m\) 个可以摆放无线路由器的位置。
你可以在这些位置中选择至多\(k\) 个增设新的路由器。
你的目标是使得第 \(1\) 个路由器和第 \(2\)个路由器之间的网络连接经过尽量少的中转路由器。
请问在最优方案下中转路由器的最少个数是多少?
输入格式
第一行包含四个正整数 \(n,m,k,r\)。
接下来 \(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\)个路由器最少经过的中转路由器的个数。
数据范围
\(2≤n≤100,1≤k≤m≤100,1≤r≤10^8\)
输入样例:
5 3 1 3
0 0
5 5
0 3
0 5
3 5
3 3
4 4
3 0
输出样例:
2
题目分析
\(bfs+dp\) 或 树形\(dp\)
先建图,将可以通信的两点间连线,因为\(n \le 100\) 所以用邻接矩阵存就行
然后对于图上的点来说,有两类,一类是有花费的,另一类是无花费的。
然后我们求走有花费的点的最短路
这道题很像NOIP 2017 普及组T3 棋盘
其实抽象一下,就是类似于有步数限制的单源汇最短路,但不是所有点都有花费
那么我们就得有两个状态,一个是走到点的单源汇最短路,另一个是花费,且最后结果花费要小于\(k\)
由此想到\(dp\)
\(dp(i , j)\)表示走到\(i\)点,花费点为\(j\)的最小步数
那么对于\(dp(i , j)\)能转移的状态就是他的邻接节点,如果该点有花费,那么转移就得是\(j - - 1\)转移到\(j\)即可
至于遍历图,算单源汇最短路,那就很简单了,数据很小,用\(bfs\)就行
注:一共是\(n + m\)个点所以开\(210\)个空间
C++ 代码
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
const int N = 210;
typedef pair<int, int> PII;
int n , m , k , r;
bool is_cost[N];
PII p[N];
bool st[N][N];
int idx , dp[N][N];
bool g[N][N];
bool check(PII a , PII b)
{
int dist = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
return r >= dist;
}
void bfs()
{
memset(dp , 0x3f , sizeof dp);
dp[1][0] = 0;
queue<PII> q;
q.push({1 , 0});
while(q.size())
{
auto t = q.front();
q.pop();
int ver = t.x , cost = t.y;
if(st[ver][cost]) continue;
st[ver][cost] = true;
for(int i = 1 ; i <= idx ; i ++)
if(g[ver][i] && cost + is_cost[i] <= k && !st[i][cost + is_cost[i]] && dp[i][cost + is_cost[i]] >= dp[ver][cost] + 1)
{
dp[i][cost + is_cost[i]] = dp[ver][cost] + 1;
q.push({i , cost + is_cost[i]});
}
}
}
signed main()
{
cin >> n >> m >> k >> r;
r *= r;
int a , b;
for(int i = 1 ; i <= n ; i ++)
{
cin >> a >> b;
p[++ idx] = {a , b};
is_cost[idx] = false;
}
for(int i = 1 ; i <= m ; i ++)
{
cin >> a >> b;
p[++ idx] = {a , b};
is_cost[idx] = true;
}
for(int i = 1 ; i <= idx ; i ++)
for(int j = i + 1 ; j <= idx ; j ++)
if(check(p[i] , p[j]))
g[i][j] = g[j][i] = 1;
bfs();
int ans = 210;
for(int i = 0 ; i <= k ; i ++)
ans = min(ans , dp[2][i] - 1);
cout << ans << '\n';
}
标签:ver,int,Day3,花费,cost,CCF,CSP,dp,路由器
From: https://www.cnblogs.com/mathblog/p/18456315