201403-4 CCF 无线网络(满分代码 + 解题思路 + bfs + dp)

题目描述

在这里插入图片描述


解题思路

问题可以转换为在n + m个点中,最多选取k个新点,从1 到 2 的最短路。
首先可以双重循环遍历所有的点,计算该点与其他的点的距离是否<=r,如果<=r,则说明这两点之间可达,用邻接表进行存储该边,构建一个无向图,其中每一条边权为1,因此该题可以使用bfs来计算最短路距离
定义一个dist数组记录从1到达第i个点,其中有j个新增点的路径的最短距离。(dp思想)
使用队列存储当层节点,依次扩展下一个节点,并更新dist数组
最后答案,需要dist【2】【0~k】取min,因为不知道最短路新增了多少个点,并且最终答案要减一(因为计算的是1到2之间的点,不包括点2)


代码实现

#include <iostream>
#include <unordered_map>
#include <cstring>
#include <queue>
#include <cmath>

#define x first
#define y second

using namespace std;
typedef pair <int, int> PII;

const int N = 210, M = N * N;

PII p[N];
int h[N], ne[M], e[M], idx; //ne和e存储的是边数,每增加一条边,idx++,N个点,边数大小设为N * N
int n, m, k, r;

bool check(int a, int b)
{
    
    
    long long x = p[a].x - p[b].x;
    long long y = p[a].y - p[b].y;
    long long res1 = x * x + y * y; //不要开根号
    long long res2 =(long long) r * r; //r是int,需要转long long,否则会溢出
    return res1 <= res2;
}

void add(int a, int b)
{
    
    
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}

int bfs()
{
    
    
    queue <PII> q; //q.x存编号,q.y存已新增的点数
    q.push({
    
    1, 0}); //放入点1
    int dist[N][M];
    memset(dist, 0x3f, sizeof(dist));
    dist[1][0] = 0;
    
    while (q.size())
    {
    
    
        PII t = q.front();
        q.pop();
        
        int id = t.x, num = t.y;
        for (int i = h[id]; i != -1; i = ne[i]) //遍历该点所有可达的点
        {
    
    
            int cid = e[i];
            int cnum = num;
            
            if (cid > n) cnum ++; //当前这个点为新增点,新增点数加一
            if (cnum <= k) //如果当前新增点数<= K
            {
    
    
                if (dist[cid][cnum] > dist[id][num] + 1)
                {
    
    
                    dist[cid][cnum] = dist[id][num] + 1; //更新
                    q.push({
    
    cid, cnum});//放入
                }
            }
        }
    }
    
    int res = 0x3f3f3f3f;
    for (int i = 0; i <= k; i ++)
    {
    
    
        res = min(res, dist[2][i]);
    }
    return res - 1;
}

int main()
{
    
    
    cin >> n >> m >> k >> r;
    
    memset(h, -1, sizeof(h)); //一定要记得初始化
    
    for (int i = 1; i <= n + m; i ++)
    {
    
    
        cin >> p[i].x >> p[i].y;
    }
    
    for (int i = 1; i <= n + m; i ++)
    {
    
    
        for (int j = 1; j <= n + m; j ++)
        {
    
    
            if (check(i, j)) //若两点可达,将其连通,相当于转换为一个边长为1的无向图
            {
    
    
                add(i, j); //无向图创建两条边
                add(j, i);
            }
        }
    }

    cout << bfs();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_51800570/article/details/129112858
今日推荐