zoukankan      html  css  js  c++  java
  • 《Yuchang and Zixiang’s stones》

    题意:简化下就是给定一个n * m的棋盘,有q组询问,每次询问棋子是否能放置在该位置。

    能放置的条件就是,该位置之前没棋子,且该位置可以走到棋盘外。

    Solution:

    很明显这里是一个搜索类的问题,但是因为询问次数过多,如果对于每次询问都去搜索显然会超时。

    考虑对询问离线:假定我们目前已经放置下了所有的棋子,并且处理出此时哪些位置可以走出棋盘外,哪些不能。然后我们倒序回去拆棋子。

    当我们去拆这个棋子时,我们去查询它周围的点,是否可以走到棋盘外,若没有点可以,我们拆不拆除这个点都没有影响。

    若周围有点可以,显然拆除后这个点也可以,那么我们拆除该点。

    同时从这个点开始搜索,去更新之前无法走到,但是拆除这个点后可以走到的点。

    基于上诉思路,可以发现每个点基本只会更新一次,那么时间复杂度平摊后为O(棋子数)。

    可以发现此题可能存在一个点放置多次的情况,即我们回去处理的时候可能一个点处理多次,这个时候我只要去处理第一次放置这个位置的情况即可。

    以下是这样处理的证明:

    对于一个位置,如果它第一次放置时,就无法放置,那么显然后面再想去放置这个点更不可能可以放置,所以如果它不能放置,那么后面放置时都不会产生影响。

    如果一个位置可以放置,那么当他放置后,这个位置后序将再无法放置,且很显然若这个位置可以放置,那么他放置的时间一定是最早的时间,所以对于第一次之后的放置。

    也不会对结果产生影响。故只需要去最前面一次进行处理即可。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef __int128_t BIG;
    typedef pair<int,int> pii;
    const int N = 1e6 + 5;
    const int M = 1e3 + 5;
    const double eps = 1e-10;
    const LL Mod = 4294967296;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int n,m,b[4][2] = {1,0,-1,0,0,1,0,-1};
    int vis[M][M];
    bool isget[M][M];
    void Prework() {
        queue<pii> Q;
        memset(isget,0,sizeof(isget));
        for(int i = 1;i <= n;++i) {
            if(vis[i][1] == INF) {
                isget[i][1] = 1;
                Q.push(pii{i,1});    
            }
            if(vis[i][m] == INF) {
                isget[i][m] = 1;
                Q.push(pii{i,m});
            }
        }
        for(int i = 1;i <= m;++i) {
            if(vis[1][i] == INF) {
                isget[1][i] = 1;
                Q.push(pii{1,i});
            }
            if(vis[n][i] == INF) {
                isget[n][i] = 1;
                Q.push(pii{n,i});
            }
        }
        while(!Q.empty()) {
            pii q = Q.front();
            Q.pop();
            for(int i = 0;i < 4;++i) {
                int px = q.first + b[i][0];
                int py = q.second + b[i][1];
                if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 0 && vis[px][py] == INF) {
                    isget[px][py] = 1;
                    Q.push(pii{px,py});
                }
            }
        }
    }
    bool isdir(int i,int j) {
        if(i == 1 || i == n || j == 1 || j == m) return true;
        for(int k = 0;k < 4;++k) {
            int px = i + b[k][0];
            int py = j + b[k][1];
            if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 1) return true;
        }
        return false;
    }
    void cal(int sx,int sy,int id) {
        queue<pii> Q;
        Q.push(pii{sx,sy});
        while(!Q.empty()) {
            pii q = Q.front();
            Q.pop();
            for(int i = 0;i < 4;++i) {
                int px = q.first + b[i][0];
                int py = q.second + b[i][1];
                if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 0 && vis[px][py] > id) {
                    isget[px][py] = 1;
                    Q.push(pii{px,py});
                }
            }
        }
    }
    bool isu[M][M],tag[M][M];
    int sum = 0,f = 0;
    void dfs(int x,int y) {
        if(f) return ;
        if(x == 1 || x == n || y == 1 || y == m) f = 1;
        if(!tag[x][y]) {
            tag[x][y] = 1;
            for(int i = 0;i < 4;++i) {
                int px = x + b[i][0];
                int py = y + b[i][1];
                if(px >= 1 && px <= n && py >= 1 && py <= m && isu[px][py] == 0) dfs(px,py);
            }
        }
    }
    bool solve2(int sx,int sy) {
        f = 0;
        memset(tag,0,sizeof(tag));
        dfs(sx,sy);
        return f;
    }
    int x[N],y[N];
    void solve() {
        while(~scanf("%d %d",&n,&m)) {
            int q;scanf("%d",&q);
            for(int i = 1;i <= n;++i)
                for(int j = 1;j <= m;++j) vis[i][j] = INF;
            for(int i = 1;i <= q;++i) {
                scanf("%d %d",&x[i],&y[i]);
              /*  if(solve2(x[i],y[i]) && isu[x[i]][y[i]] == 0) {
                    printf("%d is put
    ",i);
                    sum++;
                    isu[x[i]][y[i]] = 1;
                }*/
                vis[x[i]][y[i]] = min(i,vis[x[i]][y[i]]);
            }
            Prework();
            int ans = 0;
            for(int i = q;i >= 1;--i) {
                int dx = x[i],dy = y[i];
                if(i > vis[dx][dy]) continue;
                if(isdir(dx,dy)) {
                    ans++;
                    isget[dx][dy] = 1;
                    cal(dx,dy,i);
                }
            }
            printf("%d
    ",ans);
        }
    
    }
    int main() {
        solve();
      //  system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    WPF 自定义ComboBox样式,自定义多选控件
    .net core 的网站
    grpc详细入门
    如何遍历所有程序集中的成员、类
    【C#】IDispose接口的应用
    redis集群简介
    What’s your most controversial programming opinion?
    初学PHP——欲得生受用,须下死功夫!
    Great OOP
    博客园背景特效粒子鼠标跟踪吸附
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15180978.html
Copyright © 2011-2022 走看看