201403-4 CCF wireless network (full score code + problem-solving ideas + bfs + dp)

topic description

insert image description here


problem solving ideas

The problem can be transformed into selecting at most k new points among n + m points, and the shortest path from 1 to 2.
First, you can double loop through all points, calculate whether the distance between this point and other points is <=r, if <=r, it means that the two points are reachable, use the adjacency list to store the edge, and build an undirected Graph, where the weight of each edge is 1, so this question can use bfs to calculate the shortest distance .
Define a dist array to record the shortest distance of the path from 1 to the i-th point, which has j new points. (dp idea)
Use the queue to store the nodes of the current layer, expand the next node in turn, and update the
final answer of the dist array. You need to take the min from dist [2] [0~k], because you don’t know how many points are added to the shortest path, and The final answer is subtracted by one (since the points between 1 and 2 are calculated, point 2 is not included)


Code

#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;
}

Guess you like

Origin blog.csdn.net/qq_51800570/article/details/129112858