• 2019-2020 ICPC Southwestern European Regional Programming Contest (SWERC 2019-20) L题(SG+状压)


    题意:给定一个N*N的表格,其上有三种类型的方格:坚实的地面、潮湿的区域和保护区。连通的湿区方格形成湿区,当两个正方形共用一条边时,它们被认为是连接的。每个湿区必须连接到网格的左右两侧,并且不包含超过2N的湿区方块。属于两个不同湿区的两个湿区方格之间的距离始终至少为3,距离=abs(x-dx)+abs(y-dy)。你和你的朋友将轮流在湿地旁放置一个摄像头,但有以下限制:1. 摄像机必须放在坚固的地面上。2. 相机必须靠近湿区广场,这样你才能拍到鸟的照片。3. 摄像机不得位于保护区广场上。4. 同一个方格上不能有两个摄像头。5. 同一湿区相邻的两个摄像机不能相邻(相邻的概念意味着共享一个边)。 第一个不能放置相机的玩家将输掉游戏。假设两个玩家都玩得很好,第一个玩家会赢还是输?

    输入格式:第一行一个整数N(N <= 10),接下来是一个N*N的字符矩阵,“*”代表湿区方格,‘.’代表坚实的地面,‘x’代表保护区

    输出格式:第一个玩家升输出“First player will win”,否则输出“Second player will win”

    分析:思路状压+SG。定义可以放摄像头的地面为可行方格,相邻的可行方格组成的连通块称为可行区。将每个湿区编号,注意到不同湿区方格间曼哈顿距离不小于3,故每个可行方格只与一个湿区相邻,所以一个可行区的摄像头放置情况不会影响其他可行区,所以每个可行区间可看作独立的Nim游戏,用状压分别求出SG值异或起来即可。因为湿区方格不超过2*N,所以可行区的方格数不会超过2*N,复杂度正确。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #define pb(a) push_back(a)
    const int maxn = 1e4;
    
    //st数组代表该潮湿的方格所属湿区编号,org数组表示该可行方格相邻的湿区编号 
    int N,tot,cnt,kk,SG;
    int sg[2000005],org[12][12],st[12][12],to[4][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
    char ss[12][12];
    bool vis[12][12];
    std::vector<int> x[100], y[100];
    
    inline int abs(int a) { return a < 0 ? -a : a; }
    
    // 找湿地连通块,对不同连通块进行编号 
    void dfs(int x, int y){
        for(int i = 0; i < 4; ++i){
            int dx = x + to[i][0], dy = y + to[i][1];
            if(ss[dx][dy] == '*' && !vis[dx][dy])  vis[dx][dy] = 1, st[dx][dy] = st[x][y], dfs(dx, dy);
            else if(ss[dx][dy] == '.')  org[dx][dy] = st[x][y];     //   确定可行方格所属湿区编号 
        }
    }
    
    //存下可行区中各方格坐标 
    void dfs_(int xx, int yy, int k){
        //printf("%d %d
    ", xx, yy);
        for(int i = 0; i < 4; ++i){
            int dx = xx + to[i][0], dy = yy + to[i][1];
            if(org[dx][dy] == org[xx][yy] && !vis[dx][dy]){
                vis[dx][dy] = 1;
                x[k].pb(dx), y[k].pb(dy);    //该方格属于第k个可行区 
                dfs_(dx, dy, k);
            }
        }
    }
    
    //now表示当前状压的状态,id表示可行区编号,num表示可行区内方格数 
    void get_sg(int now, int id, int num){
        if(sg[now])  return ;
        bool ok, is[maxn];
        memset(is, 0, sizeof(is));
        for(int i = 0; i < num; ++i){
            if((now & (1 << i)) == 0){
                ok = 1;
                for(int t = 0; t < num; ++t){
                    if(t == i)  continue;
                    if(abs(x[id][t] - x[id][i]) + abs(y[id][t] - y[id][i]) == 1 && (now & (1 << t))) { ok = 0;  break; }
                }
                if(ok){
                    get_sg(now | (1 << i), id, num);
                    is[sg[now | (1 << i)]] = 1;
                }
            }
        }
        for(int i = 0; i < maxn; ++i)
            if(!is[i]){
                sg[now] = i;
                return ;
            }
    }
    
    int main(){
        scanf("%d", &N);
        for(int i = 1; i <= N; ++i)  scanf("%s", ss[i]+1);
        for(int i = 1; i <= N; ++i)
            for(int t = 1; t <= N; ++t)
                if(ss[i][t] == '*' && !vis[i][t]){
                    vis[i][t] = 1, st[i][t] = ++tot, dfs(i, t);
                }
        for(int i = 1; i <= N; ++i)
            for(int t = 1; t <= N; ++t)
                if(ss[i][t] == '.' && !vis[i][t] && org[i][t]){
                    vis[i][t] = 1;
                    x[++kk].pb(i), y[kk].pb(t);
                    dfs_(i, t, kk);
                }
        for(int i = 1; i <= kk; ++i){ 
            memset(sg, 0, sizeof(sg));
            get_sg(0, i, x[i].size());
            SG ^= sg[0];
        }
        if(SG)  puts("First player will win");
        else    puts("Second player will win");
        return 0;
    }
    你只有十分努力,才能看上去毫不费力。
  • 相关阅读:
    java.nio.channels.ClosedChannelException
    问题记录【CentOS磁盘空间满】
    vue@2.5.2 对等的vue-template-compiler【Vue】
    Azkaban 常见问题记录
    DataFrame 对其列的各种转化处理
    CICD
    Git通
    Hue问题记录
    多文件的wc程序【java版】
    Caused by: java.lang.RuntimeException: java.lang.Integer is not a valid external type for schema of
  • 原文地址:https://www.cnblogs.com/214txdy/p/14024368.html
Copyright © 2020-2023  润新知