【AcWing】蓝桥杯C++ AB组辅导课

教学计划与递归


如何准备蓝桥杯比赛

  • 要有一定刷题量
    若想在省赛中取得较好成绩,建议做200题左右。
    若想在国赛中取得较好成绩,建议做300题左右。
    本课程约讲解100题左右。

  • 要重视调试
    有思路得前提下,若调试不过,不要立马问别人。要自己努力解决问题。

  • 要重视考试。
    感受真实氛围,检验学习成果。

  • 比赛时比的并不是去发明或者去创造某一个思路,比赛比的是熟练度。

做题的套路

  • 算法题特点:
    1、与数学、物理等学科相比,算法题的模型相对较少。
    2、思维量高
    3、编写编程能力 。要用理论去指导实践。数学题想出来就能做出来,但是算法题能想出来不一定能实现出来。

  • 做题过程
    1、看题目描述
    2、分析,抽象出来它考什么模型。分析出题人是想问什么。
    3、回忆之前学过的算法或做过的题目能不能解决这个问题。若不能,再去回溯。解决方案是平时多去积累一些题目,多去刷一些题目。只有平时积累的多了,考试的时候才能学以致用。

  • 如何判断一个算法能不能用?
    1、首先看正确性
    2、再看时间是否超限制。
    C++ 评测机一秒约运行一亿次。若算法的的时间复杂度超过108,则可能会超时。
    在这里插入图片描述
    做题时,先看数据范围,排除不能使用的算法。找到题目数据范围区间之内的算法。这样做题思路会更明确。
    数据范围可以带给我们非常多的信息。

  • 学算法一定要落实到代码上

  • 若输入输出 范围 小于 105 推荐用 cin / cout 否则用 scanf / printf 输入时间会快一倍左右。

第一讲 递归与递推

  • 递归是什么?递归就是自己调用自己。

递归计算斐波那契数列

#include<iostream>

using namespace std;

int f(int n )
{
    if (n == 1) return 1;
    if (n == 2) return 2;
    return f(n - 1) + f(n - 2); 
}
int main()
{
    int n ; 
    cin >> n;

    cout << f(n);
    
    return 0;
}
  • 如何分析判断 递归执行顺序
    所有递归都可以转化为一颗递归搜索树
    在这里插入图片描述
  • 记忆几个比较常用的数据
    21 = 2
    22 = 4
    23 = 8
    24 = 16
    25 = 32
    26 = 64
    27 = 128
    28 = 256
    29 = 512
    210 = 1024
    215 = 32768
    216 = 65536
    220 约等于106
    263 约等于 108

递归实现指数型枚举

在这里插入图片描述

#include<iostream>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 16;

int n;
int st[N];//状态,记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它。

void dfs(int u)
{
    if (u > n)
    {
        for (int i =1; i <= n; i ++ )
            if (st[i] == 1)
                printf("%d ", i);
        printf("\n");
        return;
    }

    st[u] = 2;
    dfs(u + 1);    //第一个分支: 不选
    st[u] = 0;	   //恢复现场

    st[u] = 1;
    dfs(u + 1);   // 第二个分支: 选
    st[u] = 0;	
}

int main()
{
    cin >> n;

    dfs(1);

    return 0;
}

变形 :如何输出所有方案?

#include<iostream>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int N = 16;

int n;
int st[N];//状态,记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它。
vector<vector<int>> ways;

void dfs(int u)
{
    if (u > n)
    {
    	vector<int> way;
        for (int i = 1; i <= n; i ++ ) // 记录方案
            if (st[i] == 1)
                way.push_back(i);
         ways.push_back(way);
        return;
    }

    st[u] = 2;
    dfs(u + 1);    //第一个分支: 不选
    st[u] = 0;	   //恢复现场

    st[u] = 1;
    dfs(u + 1);   // 第二个分支: 选
    st[u] = 0;	
}

int main()
{
    cin >> n;

    dfs(1);

	for (int i = 0; i < ways.size(); i ++ )
	{
		for (int j = 0; j < ways[i].size(); j ++) printf("%d ", ways[i][j]);
		puts(""); // puts是输出一个字符串,但是这个字符串为空,仅有一个回车。
		//相当于printf("\n"); puts("")等价于只输出回车。
	}
	
    return 0;
}

递归实现排列型枚举

  • 有两种顺序
    1、依次枚举每个数放到每个位置
    2、依次枚举每个位置放哪个数
    在这里插入图片描述
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 10;

int n;
int state[N];  // 0表示还没放数,1~n表示放了哪个数
bool used[N];  // true表示用过,false表示还未用过

void dfs(int u)
{
    if (u > n)
    {
        for (int i = 1; i <= n; i ++ ) 
        	cout << state[i] << ' ';
        cout << endl;
        return;
    }

    for (int i = 1; i <= n; i ++)
        if (!used[i])
        {
            state[u] = i;
            used[i] = true;
            dfs(u + 1);
            state[u] = 0;
            used[i] = false;
        }
}

int main()
{
    cin >> n;

    dfs(1);

    return 0;
}

递归实现组合型枚举

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 30;

int n, m;
int way[N];

void dfs(int u, int start)
{
	if (n + u - start < m) return; // 如果把后面所以的数都选上还不够m个 当前分支无解。
    if (u == m + 1)
    {
        for (int i = 1; i <= m ; i ++) printf("%d ", way[i]);
        puts("");
        return;
    }

    for (int i = start; i <= n; i ++)
    {
        way[u] = i;
        dfs(u + 1, i + 1);
        way[u] = 0;
    }
}

int main()
{
    scanf("%d%d", &n, &m);

    dfs(1, 1);

    return 0;
}

AcWing116.飞行员兄弟

第二讲 二分与前缀和

AcWing789.数的范围

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100010;

int n ,m;
int q[N];

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i ++) cin >> q[i];

    for (int i = 0; i < m; i ++)
    {
        int x;
        cin >> x;
        int l = 0, r = n - 1;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (q[mid] >= x) r = mid;
            else l = mid + 1;
        }

        if (q[r] == x) //  比较的是数组里的元素
        {
            cout << r << ' ';
            r = n - 1;
            while (l < r)
            {
                int mid = l + r + 1 >> 1;
                if (q[mid] <= x) l = mid; //**这里写mid是不对的,要写[mid]
                else r = mid - 1;
            }
            cout << l << endl;
        }
        else cout << "-1 -1" << endl;
    }

    return 0;
}

AcWing790.数的三次方根

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    double x;
    cin >> x;
    double l = -100000, r = 100000;
    while (r - l > 1e-8)
    {
        double mid = (l + r) / 2;
        if (mid * mid * mid >= x) r = mid;
        else l = mid;
    }

    printf("%.6lf", l);

    return 0;
}

在这里插入图片描述

AcWing795.前缀和

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n, m;
int a[N];
int s[N];

int main()
{
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        s[i] = s[i - 1] + a[i];
    }

    while (m --)
    {
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;        
    }
    
    return 0;
}

在这里插入图片描述

AcWing796.子矩阵的和

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m, q;
int a[N][N], s[N][N];

int main()
{
    cin >> n >> m >> q;

    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
        {
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];//++-+
        }
    
    while (q --)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;//+--+
    }

    return 0;
}
#include <iostream>

using namespace std;

const int N = 10010;

int n, m, q;
int a[N][N];
int s[N][N];

int main()
{
    cin >> n >> m >> q;
    for (int i = 1; i <= n ; i++)
        for (int j = 1; j <= m; j ++)
        {
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    
    while (q --)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        cout << s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1] << endl;
    }

    return 0;
}

AcWing1221.四平方和

#include<bits/stdc++.h>
using namespace std;
int main()  
{  
    int n,a,b,c,d;  
    scanf("%d",&n);   
    int sqn = int(sqrt(n));
    for(a=0;a<=sqn;++a)  
    {  
        for(b=a;b<=sqn;++b)  
        {  
            for(c=b;c<=sqn;++c)  
            {  
                d=sqrt(n-a*a-b*b-c*c); //这里可以有效地减少一重循环 
                if(n==a*a+b*b+c*c+d*d)  
                {  
                    if(c>d)swap(d,c);
                    printf("%d %d %d %d\n",a,b,c,d);  
                    return 0;  
                }   
            }   
        }   
    }   
}

AcWing1230.K倍区间

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
const int N = 100010;

int n, k;
LL s[N];
int cnt[N];

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i ++)
    {
        cin >> s[i];
        s[i] += s[i - 1];
    }

    LL res = 0;
    cnt[0]++;
    for (int i = 1; i <= n; i ++)
    {
        res += cnt[s[i] % k];
        cnt[s[i] % k] ++;
    }

    cout << res;
    return 0;
}

第四讲 枚举、模拟与排序

AcWing1210.连号区间数

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010, INF = 100000000;

int n;
int a[N];

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> a[i];

    int res = 0;
    for (int i = 0; i < n; i ++ )   // 枚举区间左端点
    {
        int minv = INF, maxv = -INF;
        for (int j = i; j < n; j ++ )   // 枚举区间右端点
        {
            minv = min(minv, a[j]);
            maxv = max(maxv, a[j]);
            if (maxv - minv == j - i) res ++ ;
        }
    }

    cout << res << endl;

    return 0;
}

AcWing1236.递增三元组

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int n;
int a[N], b[N], c[N];
int as[N];  // as[i]表示在A[]中有多少个数小于b[i]
int cs[N];  // cs[i]表示在C[]中有多少个数大于b[i]
int cnt[N], s[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]), a[i] ++ ;
    for (int i = 0; i < n; i ++ ) scanf("%d", &b[i]), b[i] ++ ;
    for (int i = 0; i < n; i ++ ) scanf("%d", &c[i]), c[i] ++ ;

    // 求as[]
    for (int i = 0; i < n; i ++ ) cnt[a[i]] ++ ;
    for (int i = 1; i < N; i ++ ) s[i] = s[i - 1] + cnt[i];   // 求cnt[]的前缀和
    for (int i = 0; i < n; i ++ ) as[i] = s[b[i] - 1];

    // 求cs[]
    memset(cnt, 0, sizeof cnt);
    memset(s, 0, sizeof s);
    for (int i = 0; i < n; i ++ ) cnt[c[i]] ++ ;
    for (int i = 1; i < N; i ++ ) s[i] = s[i - 1] + cnt[i];
    for (int i = 0; i < n; i ++ ) cs[i] = s[N - 1] - s[b[i]];

    // 枚举每个b[i]
    LL res = 0;
    for (int i = 0; i < n; i ++ ) res += (LL)as[i] * cs[i];

    cout << res << endl;

    return 0;
}
//暴力做法 通过了6/12 个数据
#include <iostream>

using namespace std;

const int N = 100010;

int a[N], b[N], c[N];

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++) cin >> a[i];
    for (int i = 0; i < n; i ++) cin >> b[i];
    for (int i = 0; i < n; i ++) cin >> c[i];

    int cnt = 0;
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < n; j ++)
            for (int k = 0; k < n; k ++)
                if (a[i] < b[j] && b[j] < c[k])
                    cnt ++;
    
    cout << cnt << endl;
    return 0;
}

AcWing1245.特别数的和

// int -> string
string get(int x)
{
    string res;
    int t = x % 10;
    x /= 10;
    res += t;
    return res
}

// string -> int
int uget(string s)
{
    int res = 0;
    for (int i = 0; i < s.size(); i ++)
        res = res * 10 + s[i] - '0';
    return res;
}
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    int n;
    cin >> n;

    int res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int x = i;
        while (x)
        {
            int t = x % 10; // 取出x的个位
            x /= 10;    // 删掉x的个位
            if (t == 2 || t == 0 || t == 1 || t == 9)
            {
                res += i;
                break;
            }
        }
    }

    cout << res << endl;

    return 0;
}

AcWing1204.错误票据

#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010;

int n;
int a[N];

int main()
{
    int cnt;
    cin >> cnt;
    string line;

    getline(cin, line); // 忽略掉第一行的回车 **
    while (cnt -- )
    {
        getline(cin, line);
        stringstream ssin(line);

        while (ssin >> a[n]) n ++ ;
    }

    sort(a, a + n);

    int res1, res2;
    for (int i = 1; i < n; i ++ )
        if (a[i] == a[i - 1]) res2 = a[i];  // 重号
        else if (a[i] >= a[i - 1] + 2) res1 = a[i] - 1; // 断号

    cout << res1 << ' ' << res2 << endl;

    return 0;
}

AcWing466.回文日期

在这里插入图片描述

//求四位回文数的程序
#include <iostream>

using namespace std;

int main()
{
    for (int i = 0; i < 10000; i ++ )  // 最高枚举到八位回文数
    {
        int a = i, b = i;
        for (int j = 0; j < 4; j ++ ) 
            while (b)  a = a * 10 + b % 10, b /= 10; 
            
        if (a >= 1000 && a <= 9999)
            cout << a << endl;
    }
    return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check(int date)
{
    int year = date / 10000;
    int month = date % 10000 / 100;
    int day = date % 100;

    if (!month || month > 12 || !day) return false;

    if (month != 2 && day > days[month]) return false;
    
    if (month == 2)
    {
        bool leap = year % 4 == 0 && year % 100 || year % 400 == 0;
        if (day > 28 + leap) return false;
    }

    return true;
}

int getP(int x)
{
    int a = x, b = x;
    for (int j = 0; j < 4; j ++ ) 
        a = a * 10 + b % 10, b /= 10;
    return a;
}

int main()
{
    int date1, date2;
    cin >> date1 >> date2;

    int res = 0;
    for (int i = 0; i < 10000; i ++ )
    {
        int r = getP(i);
        if (r >= date1 && r <= date2 && check(r)) res ++ ;
    }

    printf("%d\n", res);
    return 0;
}
//枚举回文数 -> 判断是否在范围内 -> 判断日期是否合法

AcWing1219.移动距离

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    int w, m, n;
    cin >> w >> m >> n;
    m --, n -- ;

    int x1 = m / w, x2 = n / w;
    int y1 = m % w, y2 = n % w;
    if (x1 % 2) y1 = w - 1 - y1;
    if (x2 % 2) y2 = w - 1 - y2;

    cout << abs(x1 - x2) + abs(y1 - y2) << endl;

    return 0;
}

AcWing1229.日期问题

思考:错在哪里了?
在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check_vaild(int year, int month, int day)
{
    if (month == 0 || month > 12 || day == 0) return false;
    if (month != 2 && day > days[month]) return false;
    if (month == 2)
    {
        bool leap = year % 4 == 0 && year % 100 || year % 400 == 0;
        if (day > 28 + leap) return false;
    }
    return true;
}

int main()
{
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);

    for (int data = 19600101; data <= 20591231; data ++)
    {
        int year = data / 10000, month = data % 10000 / 100, day = data % 100;
        if (check_vaild(year, month, day))
        {
            if (year % 100 == a && month == b && day == c ||
                month == a && day == b && year % 100 == c ||
                day == a && month == b && year % 100 == c)
                printf("%d-%02d-%02d\n", year, month, day);
        }
    }
    return 0;
}

#include <iostream>

using namespace std;

int main()
{
    int a = 123456;

    cout << a % 1000 << endl;//456
    cout << a / 1000 << endl;//123

    cout << a / 10000 << endl; // 12

    cout << a / 100 % 100 << endl;//34
    cout << a % 10000 / 100 << endl;//34

    cout << a % 100 << endl;//56
    cout << a % 10000 % 100 << endl;//56

    return 0;
}   
// 取余是得到除以此数的余数

AcWing1231.航班时间

在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int get_seconds(int h, int m, int s)
{
    return h * 3600 + m * 60 + s;
}

int get_time()
{
    string line;
    getline(cin, line);

    if (line.back() != ')') line += " (+0)";

    int h1, m1, s1, h2, m2, s2, d;
    sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);

    return get_seconds(h2, m2, s2) - get_seconds(h1, m1, s1) + d * 24 * 3600;
}

int main()
{
    int n;
    scanf("%d", &n);
    string line;
    getline(cin, line);     // 忽略掉第一行的回车
    while (n -- )
    {
        int time = (get_time() + get_time()) / 2;
        int hour = time / 3600, minute = time % 3600 / 60, second = time % 60;
        printf("%02d:%02d:%02d\n", hour, minute, second);
    }

    return 0;
}

AcWing1241.外卖店优先级

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n, m, T;
int score[N], last[N];
bool st[N];

PII order[N];

int main()
{
    scanf("%d%d%d", &n, &m, &T);
    for (int i = 0; i < m; i ++ ) scanf("%d%d", &order[i].x, &order[i].y);
    sort(order, order + m);

    for (int i = 0; i < m;)
    {
        int j = i;
        while (j < m && order[j] == order[i]) j ++ ;
        int t = order[i].x, id = order[i].y, cnt = j - i;
        i = j;

        score[id] -= t - last[id] - 1;
        if (score[id] < 0) score[id] = 0;
        if (score[id] <= 3) st[id] = false; // 以上处理的是t时刻之前的信息

        score[id] += cnt * 2;
        if (score[id] > 5) st[id] = true;

        last[id] = t;
    }

    for (int i = 1; i <= n; i ++ )
        if (last[i] < T)
        {
            score[i] -= T - last[i];
            if (score[i] <= 3) st[i] = false;
        }

    int res = 0;
    for (int i = 1; i <= n; i ++ ) res += st[i];

    printf("%d\n", res);

    return 0;
}

第六讲 双指针、BFS与图论

AcWing1238.日志统计

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;//pair 默认按第一关键字排序

const int N = 100010;

int n, d, k;
PII logs[N];
int cnt[N];
bool st[N];  // 记录每个帖子是否是热帖

int main()
{
    scanf("%d%d%d", &n, &d, &k);
    for (int i = 0; i < n; i ++ ) scanf("%d%d", &logs[i].x, &logs[i].y);

    sort(logs, logs + n);

    for (int i = 0, j = 0; i < n; i ++ ) // i < n 这里不是i < j
    {
        int id = logs[i].y;
        cnt[id] ++ ;

        while (logs[i].x - logs[j].x >= d)
        {
           	int id = logs[j].y;
            cnt[id] --; 
            j ++;
        }

        if (cnt[id] >= k) st[id] = true;
    }

    for (int i = 0; i <= 100000; i ++ )
        if (st[i])
            printf("%d\n", i);

    return 0;
}

AcWing1101.献给阿尔吉侬的花束

BFS可以找到最少步数因为BFS是按层搜索的
逻辑性的问题要一遍一遍的重复才可以记住
在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 210;

int n, m;
char g[N][N];
bool st[N][N];
PII q[N * N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

int dist[N][N];

int bfs(PII start, PII end)
{
    // queue<PII> q;
    memset(dist, -1, sizeof dist);
    memset(st, 0, sizeof st);
    int tt = 0;
    int hh = 0;

    dist[start.x][start.y] = 0; //**
    // q.push(start);
    q[0] = start;
    st[start.x][start.y] = 1;

    while (hh <= tt)
    {
        // auto t = q.front();
        // q.pop();
        PII t = q[hh ++ ];

        for (int i = 0; i < 4; i ++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m || g[x][y] == '#' || st[x][y]) continue;  // 出界
            
            dist[x][y] = dist[t.x][t.y] + 1;
            if (end == make_pair(x, y)) return dist[x][y];
            // q.push({x, y}); 
            q[++ tt] = {x, y};
            st[x][y] = true;
        }
    }

    return -1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);

        PII start, end;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == 'S') start = {i, j};
                else if (g[i][j] == 'E') end = {i, j};

        int distance = bfs(start, end);
        if (distance == -1) puts("oop!"); //  最后是有返回值的
        else printf("%d\n", distance);
    }

    return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 210;

int n, m;
char g[N][N];
int dist[N][N];
PII q[N * N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

int bfs(PII start, PII end)
{
    // queue<PII> q;
    memset(dist, -1, sizeof dist);
    int tt = 0;
    int hh = 0;

    dist[start.x][start.y] = 0;
    // q.push(start);
    q[0] = start;

    while (hh <= tt)
    {
        // auto t = q.front();
        // q.pop();
        PII t = q[hh ++ ];

        for (int i = 0; i < 4; i ++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m || g[x][y] == '#' || dist[x][y] != -1) continue;  // 出界
            
            dist[x][y] = dist[t.x][t.y] + 1;
            if (end == make_pair(x, y)) return dist[x][y];
            // q.push({x, y}); 
            q[++ tt] = {x, y};
        }
    }

    return -1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);

        PII start, end;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == 'S') start = {i, j};
                else if (g[i][j] == 'E') end = {i, j};

        int distance = bfs(start, end);
        if (distance == -1) puts("oop!"); //  最后是有返回值的
        else printf("%d\n", distance);
    }

    return 0;
}

AcWing1113.红与黑

在这里插入图片描述

#include<iostream>
#include<queue>
#include<algorithm>
#include <cstring>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
const int N = 25;

int n, m;
char g[N][N];
bool st[N][N];
PII q[N * N];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

int bfs(int sx, int sy)
{
    // queue<PII> q;
    // q.push({sx, sy});
    memset(st,0,sizeof(st));
    int tt = 0; int hh = 0;
    q[0] = {sx, sy};
    
    st[sx][sy] = true;
    // g[sx][sy] = '#';
    int res = 0;

         //q.size()
    while (hh <= tt)
    {
        // auto t = q.front();
        auto t = q[hh ++];
        // q.pop();
        res ++ ;

        for (int i = 0; i < 4; i ++)
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m || st[x][y] || g[x][y] != '.') continue;
            // q.push({x, y});
            
            q[++tt] = {x, y};
            // g[x][y] = '#';
            st[x][y] = true;
        }
    }
    return res;
}

int main()
{
    while(cin >> m >> n, n || m)
    {
        for (int i = 0; i < n; i ++) cin >> g[i];
        int x, y;
        for (int i = 0; i < n; i ++)
            for (int j = 0; j < m; j ++)
                if (g[i][j] == '@')
                {
                    x = i;
                    y = j;
                }
        cout << bfs(x, y) << endl;
    }

    return 0;
}

AcWing1224.交换瓶子

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010;

int n;
int b[N];
bool st[N];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);

    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
        if (!st[i])
        {
            cnt ++ ;
            for (int j = i; !st[j]; j = b[j])
                st[j] = true;
        }

    printf("%d\n", n - cnt);

    return 0;
}

AcWing1096.地牢大师

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

struct Point
{
    int x, y, z;
};

int L, R, C;
char g[N][N][N];
Point q[N * N * N];
int dist[N][N][N];

int dx[6] = {1, -1, 0, 0, 0, 0};
int dy[6] = {0, 0, 1, -1, 0, 0};
int dz[6] = {0, 0, 0, 0, 1, -1};

int bfs(Point start, Point end)
{
    int hh = 0, tt = 0;
    q[0] = start;
    memset(dist, -1, sizeof dist);
    dist[start.x][start.y][start.z] = 0;

    while (hh <= tt)
    {
        auto t = q[hh ++ ];

        for (int i = 0; i < 6; i ++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i], z = t.z + dz[i];
            if (x < 0 || x >= L || y < 0 || y >= R || z < 0 || z >= C) continue;  // 出界
            if (g[x][y][z] == '#') continue;  // 有障碍物
            if (dist[x][y][z] != -1) continue;  // 之前走到过

            dist[x][y][z] = dist[t.x][t.y][t.z] + 1;
            if (x == end.x && y == end.y && z == end.z) return dist[x][y][z];

            q[ ++ tt] = {x, y, z};
        }
    }

    return -1;
}

int main()
{
    while (scanf("%d%d%d", &L, &R, &C), L || R || C)
    {
        Point start, end;
        for (int i = 0; i < L; i ++ )
            for (int j = 0; j < R; j ++ )
            {
                scanf("%s", g[i][j]);
                for (int k = 0; k < C; k ++ )
                {
                    char c = g[i][j][k];
                    if (c == 'S') start = {i, j, k};
                    else if (c == 'E') end = {i, j, k};
                }
            }

        int distance = bfs(start, end);
        if (distance == -1) puts("Trapped!");
        else printf("Escaped in %d minute(s).\n", distance);
    }

    return 0;
}

AcWing1233.全球变暖

在这里插入图片描述

//while头入队标记 for尾出队统计
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

int n;
char g[N][N];
bool st[N][N];
PII q[N * N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

void bfs(int sx, int sy, int &total, int &bound)
{
    int hh = 0, tt = 0;//   (int tt =0, hh = 0;正确) (int tt, hh = 0 错误)
    
    q[0] = {sx, sy};
    st[sx][sy] = true; // 入队标记

    while (hh <= tt)
    {
    	// while循环的头部出队 for循环的尾部入队。
        PII t = q[hh ++ ];
        total ++ ; // 出队统计
        
        bool is_bound = false;
        for (int i = 0; i < 4; i ++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i]; 
            if (x < 0 || x >= n || y < 0 || y >= n || st[x][y] ) continue;  // 出界

            if (g[x][y] == '.')
            {
                is_bound = true; // 每一个点访问四个方向,只要有一个方向符合条件就满足。
                //不能直接在这里bound++ 
                continue;
            }

            q[ ++ tt] = {x, y};
            st[x][y] = true;  //入队标记
            
        }

        if (is_bound) bound ++ ;
    }
}

int main()
{
    scanf("%d", &n);

    for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);

    int cnt = 0;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            if (!st[i][j] && g[i][j] == '#')
            {
                int total = 0, bound = 0;
                bfs(i, j, total, bound);
                if (total == bound) cnt ++ ;
            }

    printf("%d\n", cnt);

    return 0;
}

AcWing1207.大臣的旅费

//用vector存储图
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
struct Edge
{
    int id, w;
};
vector<Edge> h[N];
int dist[N];

void dfs(int u, int father, int distance)
{
    dist[u] = distance;

    for (auto node : h[u])
        if (node.id != father)
            dfs(node.id, u, distance + node.w);
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        h[a].push_back({b, c});
        h[b].push_back({a, c});
    }

    dfs(1, -1, 0);

    int u = 1;
    for (int i = 1; i <= n; i ++ )
        if (dist[i] > dist[u])
            u = i;

    dfs(u, -1, 0);

    for (int i = 1; i <= n; i ++ )
        if (dist[i] > dist[u])
            u = i;

    int s = dist[u];

    printf("%lld\n", s * 10 + s * (s + 1ll) / 2);

    return 0;
}

第十一届蓝桥杯省赛第一场C++A/B组真题

AcWing2065.整除序列

#include<cstdio>

int main()
{
    long long n;
    scanf("%lld", &n);
    while(n)  printf("%lld ", n),  n >>= 1; //逗号表达式
    return 0;
}
// for(;n;n>>=1) 等价于  while(n!=0) n=n/2

AcWing2066.解码

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    string s, res;
    cin >> s;

    for (int i = 0; i < s.size(); i ++ )
        if (i + 1 < s.size() && s[i + 1] <= '9')
        {
            int k = s[i + 1] - '0';
            while (k -- ) res += s[i];
            i ++ ;
        }
        else
        {
            res += s[i];
        }

    cout << res << endl;
    return 0;
}

AcWing2067.走方格

在这里插入图片描述
注意题干要求,如果行号和列数都是偶数,不能走入这一格中。
不能走的地方不走就可以了 全局变量的整型数组默认赋值为0 所以跳过就行

#include <iostream>
#include <cstring>

using namespace std;

const int N = 40;

int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;
    f[1][1] = 1;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            if (i == 1 && j == 1) continue;
            if (i % 2 || j % 2)
                f[i][j] = f[i - 1][j] + f[i][j - 1];
        }

    cout << f[n][m] << endl;

    return 0;
}

AcWing2068.整数拼接

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
const int N = 100010;

int n, m;
int a[N], s[11][N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    for (int i = 0; i < n; i ++ )
    {
        LL t = a[i] % m;
        for (int j = 0; j < 11; j ++ )
        {
            s[j][t] ++ ;
            t = t * 10 % m;
        }
    }

    LL res = 0;
    for (int i = 0; i < n; i ++ )
    {
        LL t = a[i] % m;
        int len = to_string(a[i]).size();
        res += s[len][(m - t) % m];

        LL r = t;
        while (len -- ) r = r * 10 % m;
        if (r == (m - t) % m) res -- ;
    }

    printf("%lld\n", res);

    return 0;
}
  • 73
    点赞
  • 416
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值