Chapter6双指针,BFS和图论

Posted scl0725

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Chapter6双指针,BFS和图论相关的知识,希望对你有一定的参考价值。

Chapter6 双指针,BFS和图论

  • 双指针

1.日志统计 1238

经典的双指针模板题

所谓双指针其实就是针对多重循环的一种优化方式,缩小时间复杂度以确保不会TLE

循环的是一个时间段

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

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1e5 + 10;
int n, d, k;
bool st[N];
int cnt[N];
PII rec[N];

int main()
{
    cin >> n >> d >> k;
    for(int i = 0; i < n; i++ ) scanf("%d%d", &rec[i].x, &rec[i].y);
    
    sort(rec, rec + n);
    
    for(int i = 0, j = 0; i < n; i++ )
    {
        int id = rec[i].y;
        cnt[id]++;
        while(rec[i].x - rec[j].x >= d) cnt[rec[j].y]--, j++;//优化循环
        
        if(cnt[id] >= k) st[id] = true;
    }
    
    for(int i = 0; i <= N; i++ )
        if(st[i]) cout << i << endl;
    return 0;
}
  • BFS

1.献给阿尔吉侬的花束 1101
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 210;
char a[N][N];
int dist[N][N];
int r, c;

int bfs(PII start, PII end)
{
    queue<PII> q;
    memset(dist, -1, sizeof dist);
    
    dist[start.x][start.y] = 0;
    q.push(start);
    
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        for(int i = 0; i < 4; i++ )
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if(x < 0 || x >= r || y < 0 || y >= c) continue;
            if(dist[x][y] != -1) continue;
            if(a[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});
        }
    }
    return -1;
}

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        PII start, end;
        cin >> r >> c;
        for(int i = 0; i < r; i++ ) cin >> a[i];
        
        for(int i = 0; i < r; i++ )
            for(int j = 0; j < c; j++ )
            {
                if(a[i][j] == 'S') start = {i, j};
                if(a[i][j] == 'E') end = {i, j};
            }
        
        int distance = bfs(start, end);
        if(distance == -1) puts("oop!");
        else cout << distance << endl;
    }
    
    return 0;
}
  • 图论

1.交换瓶子 1224

找原状态下有多少个环,单独的数自己成为一个环。每次交换同一个环内的数总环的数量增加1,所以想要达到题目要求的样子需要交换n - 初始环数

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

using namespace std;

const int N = 1e4 + 10;
bool st[N];
int n, b[N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++ ) scanf("%d", b + i);
    
    int rnd = 0;
    for(int i = 1; i <= n; i++ )
        if(!st[i])
        {
            rnd++;
            for(int j = i; !st[j]; j = b[j]) st[j] = true;
        }
        
    cout << n - rnd << endl;
    return 0;
}

DFS + Floodfill

红与黑 1113

dfs实现floodfill,依次遍历每个点的周围的点然后dfs邻近的点

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

using namespace std;

const int N = 25;
char a[N][N];
bool st[N][N];
int w, h;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int bfs(int x, int y)
{
    int cnt = 1;
    st[x][y] = true;
    
    for(int i = 0; i < 4; i++ )
    {
        int m = x + dx[i], n = y + dy[i];
        if(m < 0 || m >= h || n < 0 || n >= w) continue;
        if(a[m][n] == '#') continue;
        if(st[m][n]) continue;
        
        cnt += bfs(m, n);
    }
    
    return cnt;
}

int main()
{
    while(cin >> w >> h, w || h)//w列 h行
    {
        int x, y;
        for(int i = 0; i < h; i++ ) scanf("%s", a[i]);
        
        for(int i = 0; i < h; i++ )
            for(int j = 0; j < w; j++ )
                if(a[i][j] == '@')
                {
                    x = i;
                    y = j;
                }
        
        memset(st, 0, sizeof st);
        cout << bfs(x, y) << endl;
    }
    return 0;
}
  • 习题

1.完全二叉树的权值 1240 (双指针)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;
int n, a[N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++ ) scanf("%d", a + i);
    
    LL maxn = -1e18;
    int rnd;
    for(int i = 1, d = 1; i <= n; i *= 2, d++ )
    {
        LL s = 0;
        for(int j = i; j <= n && j < i + (1 << d - 1); j++ )
            s += a[j];
        if(s > maxn)
        {
            rnd = d;
            maxn = s;
        }
    }
    cout << rnd << endl;
    return 0;
}
2.地牢大师 1096

花束的推广,三维的bfs floodfill就可以解决,较简单

比较巧妙的是bfs函数中 ss 与 ee。

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

using namespace std;

struct Point{
    int x, y, z;
};
const int N = 110;
char g[N][N][N];
Point q[N * N * N];
int dist[N][N][N];
int L, R, C;
int dx[6] = {0, 0, -1, 0, 1, 0};
int dy[6] = {0, 0, 0, 1, 0, -1};
int dz[6] = {1, -1, 0, 0, 0, 0};

int bfs(Point start, Point end)
{
    memset(dist, -1, sizeof dist);
    dist[start.x][start.y][start.z] = 0;
    int ss = 0, ee = 0;
    q[0] = start;//根节点入列
    
    while(ss <= ee)
    {
        auto t = q[ss++];
        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[++ee] = {x, y, z};
        }
    }

    return -1;
}

int main()
{
    while(cin >> 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++ )
                {
                    if(g[i][j][k] == 'S') start = {i, j, k};
                    if(g[i][j][k] == 'E') end = {i, j, k};
                }
            }
        int distance = bfs(start, end);
        if(distance == -1) printf("Trapped!
");
        else printf("Escaped in %d minute(s).
", distance);
    }
    return 0;
}
3.全球变暖 1233(bfs floodfill dfs)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

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

void bfs(int x, int y, int &total, int &bound)
{
    st[x][y] = true;
    q[0] = {x, y};
    int ss = 0, ee = 0;
    
    while(ss <= ee)
    {
        PII t = q[ss++];
        total++;
        
        bool is_bound = false;
        for(int i = 0; i < 4; i++ )
        {
            int pp = t.x + dx[i], qq = t.y + dy[i];
            if(pp < 0 || pp >= n || qq < 0 || qq >= n) continue;
            if(st[pp][qq]) continue;
            if(g[pp][qq] == '.')
            {
              is_bound = true;
              continue;   
            }
            
            q[++ee] = {pp, qq};
            st[pp][qq] = 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(g[i][j] == '#' && !st[i][j])
            {
                int total = 0, bound = 0;
                bfs(i, j, total, bound);
                if(total == bound) cnt++;
            }
            
    cout << cnt << endl;
    
    return 0;
        
}
4.大臣的旅费 1207(待补充单链表法)

找树的直径:

任取一点x,找距离x最远的点y

再找距离y最远的点z

yz距离即为数的直径

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

using namespace std;

const int N = 1e5 + 10;
struct Node
{
  int id, w;  
};
int dist[N];
int n;
vector<Node> h[N];

void dfs(int u, int father, int distance)
{
    dist[u] = distance;
    
    for(auto node : h[u])
        if(node.id != father)//防止dfs回去
            dfs(node.id, u, node.w + distance);
}

int main()
{
    cin >> 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);//无父节点,形参二任取,取-1
    
    for(int i = 1; i <= n; i++ )
        if(dist[i] > dist[u])
            u = i;
        
    int s = dist[u];
    
    printf("%lld
", s * 10 + s * (s + 1ll) / 2);
    
    return 0;
}
  • 单链表

1.单链表 826
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;
int head, e[N], ne[N], idx;

//链表初始化
void init()
{
    head = -1;
    idx = 0;
}

void add_head(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head = idx++;
}

void add_k(int k, int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx ++ ;
}

void remove(int k)
{
    ne[k] = ne[ne[k]];
}

int main()
{
    init();

    int m;
    cin >> m;
    while (m -- )
    {
        char op;
        int k, x;
        cin >> op;
        if (op == 'H')
        {
            cin >> x;
            add_head(x);
        }
        else if (op == 'I')
        {
            cin >> k >> x;
            add_k(k - 1, x);
        }
        else
        {
            cin >> k;
            if (!k) head = ne[head];
            else remove(k - 1);
        }
    }

    for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
    cout << endl;

    return 0;
}

以上是关于Chapter6双指针,BFS和图论的主要内容,如果未能解决你的问题,请参考以下文章

双指针,BFS和图论

图论:平面图和图的着色

图论基础知识-什么是图和图的分类

P2196 [NOIP1996 提高组] 挖地雷DP和图论的简单结合

图论BFS(Breath First Search)Algorithm广度优先搜索遍历空间平面网格图路径选择,networkx,Python

算法学习笔记 二叉树和图遍历—深搜 DFS 与广搜 BFS