2022-01-20每日刷题打卡

2022-01-20每日刷题打卡

一本通

1215:迷宫

【题目描述】

一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n×nn×n的格点组成,每个格点只有22种状态,.#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。如果起点或者终点有一个不能通行(为#),则看成无法办到。

【输入】

第1行是测试数据的组数kk,后面跟着kk组输入。每组测试数据的第11行是一个正整数n(1≤n≤100)n(1≤n≤100),表示迷宫的规模是n×nn×n的。接下来是一个n×nn×n的矩阵,矩阵中的元素为.或者#。再接下来一行是44个整数ha,la,hb,lbha,la,hb,lb,描述A处在第haha行, 第lala列,B处在第hbhb行, 第lblb列。注意到ha,la,hb,lbha,la,hb,lb全部是从00开始计数的。

【输出】

kk行,每行输出对应一个输入。能办到则输出“YES”,否则输出“NO”。

【输入样例】

2
3 
.## 
..# 
#.. 
0 0 2 2 
5 
.....
###.#
..#.. 
###..
...#. 
0 0 4 0
【输出样例】
YES 
NO

深度搜索,以起点为开始,看它的上下左右四个点是否能通行(没有走过而且路不为‘#’,如果能,就把那个坐标为起点送去下次的深搜,直到找到坐标和目标点一样的点为止,输出yes,或者找完所有能走的路发现到不了就输出no。

#include
using namespace std;
#include
#include
#include

const int N = 110;
int n, a, b, c, d;
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 },st[N][N];
bool flag = false;

void dfs(int x,int y)
{
    if (flag)return;
    if (x == c && y == d)
    {
        cout << "YES" << endl;
        flag = true;
        return;
    }
    
    for (int i = 0; i < 4; i++)
    {
        int xx= x + dx[i], yy = y + dy[i];
        if (xx >= 0 && xx < n && yy >= 0 && yy < n && st[xx][yy] == 0 )
        {
            
            st[xx][yy] = 1;
            dfs(xx, yy);
        }
    }
}

int main()
{
    char s;
    int k;
    cin >> k;
    while (k--)
    {
        flag = false;
        memset(st, 0, sizeof st);
        cin >> n;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                cin >> s;
                if (s == '#')
                {
                    st[i][j] = 1;
                }
            }
        cin >> a >> b >> c >> d;
        if (st[a][b]==1 || st[c][d]==1)
        {
            cout << "NO" << endl;
            continue;
        }
        dfs(a, b);
        if (!flag)
        {
            cout << "NO" << endl;
        }
    }

    return 0;
}
1219:马走日

【题目描述】

马在中国象棋以日字形规则移动。

请编写一段程序,给定n×m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

【输入】

第一行为整数T(T < 10),表示测试数据组数。

每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标n,m,x,y。(0≤x≤n-1,0≤y≤m-1, m < 10, n < 10)。

【输出】

每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,0为无法遍历一次。

【输入样例】

1
5 4 0 0
【输出样例】
32

深度搜索,这里的方向和之前的上下左右不同了,走日字一共有八种方向,每次判断当前点往八个方向走有没有可以通行的点(没走过的)如果有,就以那个点为起点继续下一次判断,并把那个点的状态更改为已通行,准备两个计数器,一个ans记录走过的点,一个res记录所有的走法,每遍历一个点,ans++,当ans==n*m时,res++。有一点要注意的是,ans初始是1而不是0,因为一开始的起点也算我们遍历过的点,所以起点的状态也要更改为已通行。

#include
using namespace std;
#include
#include
#include

const int N = 15;
int n, m, res = 0;
int d[8][2] = { {1,2},{-1,2},{1,-2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1} }, st[N][N];

void dfs(int x, int y,int ans)
{
    if (ans == n * m)
    {
        res++;
        return;
    }
    for (int i = 0; i < 8; i++)
    {
        int a = x + d[i][0], b = y + d[i][1];
        if (a >= 0 && a < n && b >= 0 && b < m && st[a][b] == 0)
        {
            st[a][b] = 1;
            dfs(a, b, ans + 1);
            st[a][b] = 0;
        }
    }
}

int main()
{
    int k,ans;
    cin >> k;
    while (k--)
    {
        int x, y;
        res = 0;
        memset(st, 0, sizeof st);
        ans = 1;
        cin >> n >> m >> x >> y;
        st[x][y] = 1;
        dfs(x, y, ans);
        cout << res << endl;
    }

    return 0;
}

蓝桥杯——算法提高

算法提高 阴谋

问题描述

第四次圣杯战争开始了。 为了收集敌人的情报,言峰绮礼命令他的使魔Assassin将自己的灵体分成n份,分别监视教堂外的长直走道。
  Assassin每份灵体的能力不同。 第i份灵体可以监视到的区域是闭区间[ai,bi]。
  绮礼想知道,监控范围内的区域的总长度是多少。
  比如,第一份灵体的视野是[−1,1],第二份灵体的视野是[0,2],第三份灵体的视野是[3,4]。 那么绮礼能获得的全部视野是[−1,2]∪[3,4],长度为4。

输入格式

第1行有一个整数,表示灵体数量n。 接下来有n行,每行两个整数ai和bi,表示第i个灵体的视野为[ai,bi]。

输出格式

输出一个整数s,表示获得的全部视野的总长度。

样例

plot.in
  3
  3959 21659
  8666 26551
  3392 11450

plot.out
  23159

解释:[3959,21659]∪[8666,26551]∪[3392,11450]=[3392,26551]
  总长度为 26551−3392=23159

数据规模和约定

30% 灵体数量1<=n<=50,每份灵体的视野1<=ai,bi<=210^6
  100% 灵体数量1<=n<=10000,每份灵体的视野1<=ai,bi<=2
10^9

圣杯战争草,话说咒腕的分身有10000个吗。

这题和算法提高 长度统计其实是一样的题(我直接复制之前的答案,改了个数据类型就过了),只不过这题的数太大,要用long long类型。

自定义排序规则,以每个区间的左端点为基准升序排序。然后遍历所有区间,如果当前区间的右端点大于等于下一个区间的左端点,则说明这两个区间可以合并,比如[1,2] 和[2,4]这两个区间就可以合并成[1,4],这样总的覆盖长度就是3,但要注意,合并区间并不是单纯的当前区间的左端点和下一个区间的右端点,这样是错误的,比如[1,4]和[2,3]区间,如果是用当前区间的左端点和下一个区间的右端点合并,那结果就是[1,3],但我们知道这结果是错误的,应该是[1,4],所以合并区间的规则应该是遍历过的区间中最小的数为左端点,最大数为右端点。最后计算差值并累计起来输出即可。

#include
using namespace std;
#include
#include
#include

typedef long long ll;
typedef pairPII;

bool cmp(PII a, PII b)
{
    return a.first < b.first;
}

int main()
{
    int n;
    vectorv;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        ll a, b;
        cin >> a >> b;
        vectorv1;

        v.push_back({ a,b });
    }

    sort(v.begin(), v.end(), cmp);
    ll ans = 0;
    ll i = 0, j = 0, star = v[i].first, end = v[i].second;
    while (i < n)
    {
        if (j + 1 < n && end >= v[j + 1].first)
        {
            end = max(end, v[j + 1].second);
            j++;
        }
        else
        {
            ans += end - star;
            j++;
            if (j >= n)break;
            star = v[j].first;
            end = v[j].second;
            i = j;
        }
    }
    cout << ans << endl;

    return 0;
}

你可能感兴趣的:(c++,深度优先,算法,贪心算法,排序算法)