【蓝桥杯专题】双指针 BFS 图论 (C++ | 洛谷 | acwing | 蓝桥)


在这里插入图片描述

【蓝桥杯专题】(C++ | 洛谷 | acwing | 蓝桥)

双指针 日志统计

  • 暴力写法:
    在这里插入图片描述

链接 链接

  • 思路 : 不断优化 缩减区间 , 具体看代码注释
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 100010;   //根据题目数据范围,定N大小,此题则主要根据N,ts,id来确定的
typedef pair<int, int> PII; //定义一个PII类型以及一对int整型用于存储ts和id

#define x first //为了代码简洁,则分别把first, second 宏定义为x, y
#define y second
int n, d, k;
int cnt[N]; //用于存储每个id号获得赞数,所以后面代码为cnt[t] ++;
bool st[N]; //用于存储每个帖子是否是热帖,所以用bool类型
PII logs[N];//用于存储日志ts, id

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

    sort(logs, logs + n);

    for(int i = 0, j = 0; i < n; i ++)//双指针算法,i在前,j在后
    {
    
    
        int t = logs[i].second;//把每个获赞的帖子id存入t
        cnt[t] ++;//获得一个赞,所以此刻 ++;
        while(logs[i].first - logs[j].first >= d)//如果俩个帖子时间相差超过d,说明该赞无效
        {
    
    
            cnt[logs[j].second] --;//所以此刻--;
            j ++;//要把指针j往后,否则死循环
        }
        if(cnt[t] >= k) st[t] = true; //如果该id贴赞超过k,说明是热帖
    }
    for(int i = 0; i < 100000; i ++)
    {
    
    
        if(st[i])//如果为真,则把热帖的id打印出来
            cout << i << endl;
    }

    return 0;
}


bfs献给阿尔吉侬的花束 (BFS 模板t)

BFS 通常用于求解——》 最短路径
链接 链接


#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
typedef pair<int, int> PII;

const int N = 210;

char a[N][N];
int dis[N][N];

void bfs(PII start) {
    
    
    queue<PII> q;
    q.push(start);//队头队,对应步骤1
    while(!q.empty()) {
    
    
        PII u = q.front();
        q.pop();
        int dx[4] = {
    
    -1, 0, 1, 0};
        int dy[4] = {
    
    0, 1, 0 ,-1};
        for(int i = 0; i < 4; i++) {
    
    //遍历四个方向,对应步骤2
            int x = u.first + dx[i];
            int y = u.second + dy[i];
            if(a[x][y] == '#') continue;//如果是'#',不做任何处理
            if(a[x][y] == '.') {
    
    //如果是 '.',更新对应内容
                dis[x][y] = dis[u.first][u.second] + 1;
                a[x][y] = '#';
                q.push({
    
    x, y});
            }
            if(a[x][y] == 'E') {
    
    //如果是'E',找到了,输出
                cout << dis[u.first][u.second] + 1 << endl;
                return;
            }
        }
    }
    cout << "oop!" << endl;//没有找到
}

int main() {
    
    
    int t;
    cin >> t;
    while(t--) {
    
    
        memset(a, '#', sizeof(a));//初始化地图,各个点都是墙。
        memset(dis, 0, sizeof(dis));//初始化dis
        int n,m;
        PII start;
        cin >> n >> m;
        for(int i = 1; i <= n; i++)  {
    
    //从第一行存储地图,因为四周都是墙,bfs时,可以不做越界判断
            for(int j = 1; j <= m; j++)  {
    
    //从第一;列存储地图,因为四周都是墙,bfs时,可以不做越界判断
                cin >> a[i][j];
                if(a[i][j] == 'S')//记录下起点位置。
                start.first = i, start.second = j, a[i][j] = '#';
            }
        }
        bfs(start);
    }
    return 0;
}

1113. 红与黑 (BFS)

#include<iostream>
#include<cstring>
#include<cstdio>
#include <limits.h>
#include<algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,  int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n";
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N  = 30;
#define x first
#define y second


char g[N][N];
int cnt[N][N];

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

int bfs (PII s) {
    
    
    int res = 1;
    queue<PII> q;
    q.push(s);
    while(!q.empty()) {
    
    
        auto t = q.front();
        q.pop();
        for(int i = 0; i < 4; i ++) {
    
    
            int xx = dx[i] + t.x , yy = dy[i] + t.y;
            if(g[xx][yy] == '#') continue;
            if(g[xx][yy] == '.') {
    
    
                // cnt[xx][yy] = cnt[t.x][t.y] + 1;
                g[xx][yy] = '#';
                q.push({
    
    xx, yy});
                res ++ ;
            }
        }
    }
    return res;
}

void solve () {
    
    
    int n, m;
    while(cin >> n >> m) {
    
    
        if(n == 0 && m == 0) break;
        memset(g, '#', sizeof g);
        // memset(cnt , 0, sizeof cnt);
        PII s;
        rep(i , 1, m) {
    
    
            rep(j , 1, n) {
    
    
                cin >> g[i][j];
                if(g[i][j] == '@') {
    
    
                    s.x = i;
                    s.y = j;
                    g[i][j] = '#';
                }
            }
        }
        cout << bfs(s) <<endl;
    }

}

int main(void){
    
    
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

完全二叉树的权重 【双指针 O(nlogn)】

链接 链接
一个数据结构题 : 完全二叉树的最右边的节点为 2 * i - 1 最左的节点为 2depth

#include<iostream>
#include<cstring>
#include<cstdio>
#include <limits.h>
#include<algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,  int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n"
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N  = 30;
#define x first
#define y second

int a[N];
int cnt[N];

ll minn = INF;
ll maxx = -INF;

void solve () {
    
    
    int n;
    rep(i , 1 , n) cin >> a[i];
    
    int depth = 0;
    for(int d = 1, i = 1; i <= n; i *= 2, d ++) {
    
    
        ll s = 0;
        for(int j = i; j < i + (1 << d - 1) && j <= n; j ++) {
    
    
            s += a[i];
        }
        if(s > maxx) {
    
    
            maxx = s;
            depth = d;
        }
    }
    cout << depth << endl;
    // for(int i = 1; i < n ; i+)
}

int main(void){
    
    
// 	freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

地牢大师

链接 链接
思路 : 三维坐标, 用结构体存储 , queue 用不了 可以模拟队列 hh 头指针 tt 尾指针 https://www.acwing.com/video/257/

在这里插入图片描述

**判断 越界就 continue
能走 就 dis + 1

左孩子右兄弟

题目链接
左孩子右兄弟表示法是一种将树转化成一颗二叉树的方法;
该方法将某节点的所有兄弟节点都定位该节点的右孩子, 将该节点的任意一个孩子定位左孩子;
题目要求能够造出二叉树的最大深度;

经过观察可得, 某一层节点能够形成的深度其实就是该节点的兄弟的数量;
因此要使树的深度最深, 则树的向下构造节点的孩子数量要尽量多;
状态表示f[i] : 表示i节点作为根节点能够形成二叉树的高度;
对哪一个节点向下构造做分类: f[i] = max(f[j]) + cnt;(cnt为i节点的孩子数量)
初始化:无;
答案: f[1];



#include <cstring>
#include <iostream>
#include <algorithm>
const int N =  1e5 + 10;
using namespace std;

int n;
int h[N], ne[N], e[N], idx = 0;
int f[N];

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

void dfs(int x) {
    
    
    int cnt = 0;
    for(int i = h[x]; i != -1; i = ne[i]) {
    
    
        int j = e[i];
        dfs(j);
        cnt ++;
        f[x] = max(f[x], f[j]);
    }
    f[x] += cnt;
}

void solve () {
    
    
    cin >> n;
    memset(h, -1 , sizeof h);
    for(int i = 2; i <= n; i ++) {
    
    
        int v;
        cin >> v;
        add(v, i);
    }
    dfs(1);
    cout << f[1] << endl;
}

int main(void){
    
    
	// freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

国际象棋

题目链接

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,  int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n"
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N  = 110;
const int M = N * 2;
#define x first
#define y second

int dx[8] = {
    
    -2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {
    
    1, 2, 2, 1, -1, -2, -2, -1};
int cnt [N][N];

int res = 0;
int n, m , k;

void dfs(int x, int y, int sum) {
    
    
    if(sum == k) {
    
    
        res = (res + 1) % mod;
        return ;
    }
    if(y > m) {
    
    
        y = 1, x ++;
        if(x > n) return ;
    }

    dfs(x, y + 1, sum); // 不放马

    if(!cnt[x][y]) {
    
    
        cnt[x][y] ++;
        for(int i = 0; i < 8; i ++) {
    
    
            int a = x + dx[i], b = y + dy[i];
            if(a < 1 || a > n || b < 1 || b > m) continue;
            cnt[a][b]++;
        }
        dfs(x, y + 1, sum);
        cnt[x][y] --;
        for(int i = 0; i < 8; i ++) {
    
    
            int a = x + dx[i], b = y + dy[i];
            if(a < 1 || a > n || b < 1 || b > m) continue;
            cnt[a][b] --;
        }
        // cnt[x][y] --;
    }

}

void solve () {
    
    
    cin >> n >> m >> k;
    dfs(1, 1, 0);
    cout << res  << endl;
}

int main(void){
    
    
	// freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

AcWing 3768. 字符串删减(每日一题)

题目 链接

在这里插入图片描述

  • 经典 双指针算法
  • 特别留意 当字符被删除的时候,字符串的每一个字符下标都是会发生变化的 , 因此可以联系到双指针
#include <iostream>
#include <cstring>
#include <algorithm>

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

using namespace std;


int main ( ) {
    
    
    int n;
    string s;
    cin >>n >>s;
    int ans = 0;
    for (int i = 0; i < n; i ++ ) {
    
    
        if(s[i] != 'x') continue;
        int j = i + 1;
        while(j < n && s[j] == 'x') j ++;
        ans += max(0, j - i - 2);
        i = j - 1;
    }
    cout << ans << endl;
    return 0;
}
int main ( ) {
    
    
    int n;
    string s;
    cin >>n >>s;
    int ans = 0;
    for (int i = 0; i < n; i ++ ) {
    
    
        if(s[i] != 'x') continue;
        int j = i + 1;
        while(j < n && s[j] == 'x') j ++;
        ans += max(0, j - i - 2);
        i = j - 1;
    }
    cout << ans << endl;
    return 0;
}

799. 最长连续不重复子序列

题目 链接
在这里插入图片描述

  • 双指针模板题
  • 结合哈希数组 , 如果这个数重复出现的话 , 就 减去当前这个数 并将后指针 +1
  • 然后把每次的 res 加上 i - j + 1 即可
#include <iostream>
using namespace std;

const int N = 100010;
int a[N], cnt[N];
int n, ans;

int main() {
    
    
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
    
    
        scanf("%d", &a[i]);
    }
    for (int i = 0, j = 0; j < n; j++) {
    
    
        cnt[a[j]] ++;
        while (cnt[a[j]] > 1) {
    
    
            cnt[a[i]] --;
            i++;
        }
        ans = max(ans, j - i + 1);
    }
    printf("%d", ans);
    return 0;
}

最大数字

题目 链接


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

char c[20];
LL ans=0;

//n:1号操作剩余次数  m:2号操作剩余次数
int n,m;

void dfs(int i,LL v){
    
    
    int x=c[i]-'0'; 
    if(c[i]){
    
    
        //应该使用的操作次数
        int t = min(n,9-x);
        n-=t;
        dfs(i+1,v*10+x+t);
        //回溯
        n+=t;
        //考虑操作2是否能够使用
        if(m>x){
    
    
            m-=x+1;
            dfs(i+1,v*10+9);
            //回溯
            m+=x+1;
        }
    }else{
    
    
        //答案取max
        ans=max(ans,v);
    }
}



int main() 
{
    
    
    scanf("%s%d%d",c,&n,&m);
    dfs(0,0);
    printf("%lld\n",ans);
    return 0;
}

叶子节点 (周赛T)

题目 链接

  • 对于一个叶子节点,如果从该节点到根节点的路径(包括两端节点)中有超过 m
  • 个黑色节点连续的排列在一起,则称该节点为无效叶子节点。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,  int> PII;
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define per(i, a, n) for(int i = n; i <= a; i --)
#define pb push_back
#include <stdlib.h> // atoi
#define debug cout<<"debug"<<"\n"
#define endl "\n"
const int INF = 0x3f3f3f3f;
const int mod=1e9+7;
const int N  = 100010;
const int M = N * 2;
#define x first
#define y second

// 对于一个叶子节点,如果从该节点到根节点的路径(包括两端节点)中有超过 m
//  个黑色节点连续的排列在一起,则称该节点为无效叶子节点。

int n,m, w[N], res;
int e[M], h[N], ne[M], idx;
bool vaild, st[N];


void add (int a, int b) {
    
    
    e[idx] = b,ne[idx] = h[a], h[a] = idx ++;
}
//a当前节点  fa父节点  cnt统计非法节点  叶子节点是否为非法节点

int dfs(int u, int fa, int cnt, bool vaild) {
    
    
    if(w[u]) cnt ++ ; //  如果当前节点是黑节点
    else cnt ++;
    
    if(cnt > m ) vaild = false;
    int res = 0, sons = 0;
    for(int i = h[u]; i != -1; i = ne[i]) {
    
    
        int j = e[i];
        if(j == fa) continue;
        sons ++;
        res += dfs(j, u, cnt , vaild); // 递归下一个节点
    }
    if(!sons && vaild) res ++; // 非法节点且字节点为叶子节点 
    return res;
}

void solve () {
    
    
    cin >> n >> m;
    memset(h, -1 , sizeof h);
    for(int i = 1;  i <= n; i ++) cin >> w[i];
    for(int i = 0; i < n - 1; i ++) {
    
    
        int a ,b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }
    cout << dfs(1, -1 , 0, true) << endl;
}

int main(void){
    
    
	// freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T = 1;
    // cin >> T;
	while(T --) solve();
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_49486457/article/details/129669124
今日推荐