Sentry Robots

本文探讨了如何利用机器人在网格中守护多个兴趣点,并通过算法计算出所需的最少机器人数量。考虑到了障碍物的影响,确保每台机器人面对其负责的兴趣点且无障碍阻挡。通过解析输入的点和障碍物位置,实现有效的机器人部署策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

We need to guard a set of points of interest using sentry robots that can
not move or turn. We can position a sentry at any position facing either
north, south, east or west. Once a sentry is settled, it guards the points of
interest that are infront of it. If two or more points are in the same row
or column a single robot can guard them all. Unfortunately, there are also
some obstacles that the robot cannot see through.
From a set of points of interest and obstacles lying on a grid, calculate
the minimum number of robots needed to guard all the points. In order to guard a point of interest, a
robot must be facing the direction of this point and must not be any obstacles in between.
Given the following grid, where # represents an obstacle and * a point of interest, the minimum
number of robots needed is 2 (a possible position and orientation is shown using arrows for each robot).
Note that this is not the actual input or output, just a figure.
For the following grid we need 4 robots because of the obstacles.
Input
The first line of the input has an integer C representing the number of test cases that follow. Before
each test case there is an empty line.
For each case, the first line has 2 integers, Y and X, representing the height and width of the grid.
The next line has an integer that indicates the number of points of interest P. The following P lines
will have the positions py and px of the points of interest, one point per line. The next line has an
integer that indicates the number of obstacles W. The following W lines will have the positions wy
and wx of an obstacle, one per line.
Output
For each test case print the minimum number of robots needed to guard all the points of interest, one
per line.
CONSTRAINTS:
1 ≤ C ≤ 50
1 ≤ Y, X ≤ 100
0 ≤ P ≤ Y ∗ X
0 ≤ W ≤ Y ∗ X
0 ≤ P + W ≤ Y ∗ X
1 ≤ px, wx ≤ X
1 ≤ py, wy ≤ Y
Sample Input
2
4 6
4
2 2
2 4
4 2
4 4
3
2 3
3 3
4 3
4 5
6
1 2
1 3
2 4
2 2
3 3
4 3
2
2 3
3 2
Sample Output
2
4
这个和之前写的扫射差不多,注意到(一般都注意不到- -,这个简单一点)向左打和向右打是无区别的,向上和向下也是,所以直接解析为向右和向下,然后做标记,连接,匹配,最后出来答案。具体原理之前博文说过了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
#include<cmath>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
int a[105][105], l[105][105], r[105][105];
int leap[505][505], vis[505], g[505], x, y, numl, numr;
bool find(int x)
{
    int i, j;
    for (j = 1; j <= numr; j++){
        if (leap[x][j] && !vis[j]){
            vis[j] = 1;
            if (g[j] == 0 || find(g[j])){
                g[j] = x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int i, j, m, n, ans, t;
    cin >> t;
    while (t--)
    {
        cin >> y >> x;
        memset(a, 0, sizeof(a));
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        memset(leap, 0, sizeof(leap));
        int c;
        cin >> c;
        for (i = 1; i <= c; i++){
            cin >> m >> n;
            a[m][n] = 1;
        }
        cin >> c;
        for (i = 1; i <= c; i++){
            cin >> m >> n;
            a[m][n] = 2;
        }
        int cnt = 1, flag1, flag2;
        for (i = 1; i <= y; i++){
            flag1 = 0; flag2 = 0;
            for (j = 1; j <= x; j++){
                if (a[i][j] == 1&&!flag2){
                    flag1 = 1;
                    l[i][j] = cnt;
                    numl = cnt;
                }
                else if (a[i][j] == 1){
                    cnt++;
                    numl = cnt;
                    l[i][j] = cnt;
                    flag2 = 0;
                }
                else if (a[i][j] == 2 && flag1)flag2 = 1;
            }
            if (flag1)cnt++;
        }
        cnt = 1;
        for (j = 1; j <= x; j++){
            flag1 = 0; flag2 = 0;
            for (i = 1; i <= y; i++){
                if (a[i][j] == 1&&!flag2){
                    flag1 = 1;
                    r[i][j] = cnt;
                    numr = cnt;
                }
                else if (a[i][j] == 1)
                {
                    cnt++; numr = cnt;
                    r[i][j] = cnt;
                    flag2 = 0;
                }
                else if (a[i][j] == 2 && flag1)flag2 = 1;
            }
            if (flag1)cnt++;
        }
        for (i = 1; i <= y; i++)
        for (j = 1; j <= x; j++)
        if (l[i][j] && r[i][j])
            leap[l[i][j]][r[i][j]] = 1;
        memset(g, 0, sizeof(g));
        ans = 0;
        for (i = 1; i <= numl; i++){
            memset(vis, 0, sizeof(vis));
            if (find(i))ans++;
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值