zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    使用SocketAsyncEventArgs犯的低级错误
    使用Beetle简单构建高性能Socket tcp应用
    构造BufferWriter和BufferReader实现高效的对象序列化和反序列化
    c#编写高性能Tcp Socket应用注意事项
    文件上传下载流程设计
    识别支点
    interface 与 delegate
    小知识:ADO.NET中的连接池
    解决问题
    IBM把Rational这个软件彻底给毁了
  • 原文地址:https://www.cnblogs.com/scl0725/p/12491955.html
Copyright © 2011-2022 走看看