• Luogu 1764 翻转游戏


    题目描述

    kkke在一个n*n的棋盘上进行一个翻转游戏。棋盘的每个格子上都放有一个棋子,每个棋子有2个面,一面是黑色的,另一面是白色的。初始的时候,棋盘上的棋子有的黑色向上,有的白色向上。现在kkke想通过最少次数的翻转,使得棋盘上所有的棋子都是同一个颜色向上的(即全是黑色向上的,或全是白色向上的)。每次翻转的时候,kkke可以选择任意一个棋子,将它翻转,同时,与它上下左右分别相邻的4个棋子也必须同时翻转。

    输入输出格式

    输入格式:

    输入的第一行是一个整数n,表示棋盘是n*n的,

    接下来有n行,每行包括n个字母,表示初始的棋盘状态。如果字母是w,则表示这个棋子当前是白色向上的,如果字母是b,则表示这个棋子当前是黑色向上的。

     

    输出格式:

    输出为一行,如果无法翻转出目标状态,则输出“Impossible”,否则输出一个整数,表示kkke最少需要翻转的次数。

    输入输出样例

    输入样例#1:
    4
    bwwb
    bbwb
    bwwb
    bwww
    
    输出样例#1:
    4

    说明

    【数据范围】

    对于30%的数据,1<=n<=4

    对于100%的数据,1<=n<=16

    题解

      看到这一题, 我试了试 IDA*, 看看能水几分, 没想到只能水30, 果断滚粗。

      直接爆搜显然是会TLE 的, 那么只能考虑其他办法。

      那么我们枚举第一行的翻转, 并把翻转后的图记录, 进行第二行的搜索。

      由于第一行已经不能再翻, 如果第一行存在没有达到目标 颜色的棋子,只能由第二行来翻转。

      所以可以根据第一行的颜色 来 给第二行进行翻转, 并且可能性仅一种。

      这样一直翻转到最后一行结束, 那么除了最后一行 其他棋子 一定达到了目标颜色。

      最后再判断最后一行棋子是否都达到了目标颜色, 如果达到了就更新答案。

    代码

    原谅我丑的不行的代码

     1 #include<cstring>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #define rep(i,a,b) for( int i = (a); i <= (b); ++i )
     5 #define per(i,a,b) for( int i = (a); i >= (b); --i )
     6 using namespace std;
     7 
     8 const int N = 20, inf = ~0U >> 1;
     9 
    10 int n, mp[N][N], ans, tmp[N][N];
    11 char s[N];
    12 
    13 int cal( int x , int pos ) {
    14     return (x >> pos) & 1; 
    15 }
    16 
    17 int work( int re , int col) {
    18     rep( i, 1, n - 1 ) rep( j, 0, n - 1 ) if( tmp[i - 1][j] != col ){
    19         re++;
    20         tmp[i][j] ^= 1;
    21         tmp[i + 1][j] ^= 1;
    22         if(j) tmp[i][j - 1] ^= 1;
    23         if(j != n - 1) tmp[i][j + 1] ^= 1;
    24     }
    25     rep( j, 0, n - 1 ) if( tmp[n - 1][j] != col ) return inf;
    26     return re;
    27 }
    28 
    29 int dfs() {
    30     int re = inf;
    31     rep( i, 0, (1 << n) - 1 ) rep( col, 0, 1){
    32         rep( j, 0, n - 1 ) rep( k, 0, n - 1 ) tmp[j][k] = mp[j][k];
    33         int cnt = 0;
    34         rep( j, 0, n - 1 ) if( cal( i, j ) ) cnt++;
    35         rep( j, 0, n - 1 ) if( cal( i, j ) ^ cal( i , j - 1 ) ^ cal( i, j + 1 ) ) tmp[0][j] ^= 1;
    36         rep( j, 0, n - 1 ) if( cal( i, j ) ) tmp[1][j] ^= 1;
    37         re = min( re, work(cnt, col) );
    38     }
    39     return re;
    40 }
    41 
    42 int main()
    43 {
    44     scanf("%d",&n);
    45     rep( i, 0, n - 1 ) {
    46         scanf("%s",s);
    47         rep( j, 0, n - 1 ) mp[i][j] = s[j] == 'w';
    48     }
    49     ans = dfs();
    50     if( ans == inf ) printf("Impossible
    ");
    51     else printf("%d
    ", ans);
    52 }
    View Code
  • 相关阅读:
    延迟任务的实现方式
    brpc的安装20220620可用
    tmux和zsh的个性化配置针对无法连接外网的机器
    VimForCpp离线安装
    记录一个vim配置
    LeetCode No1051. 高度检查器
    LeetCode No890. 查找和替换模式
    LeetCode No63. 不同路径 II
    LeetCode No64. 最小路径和
    个人资料
  • 原文地址:https://www.cnblogs.com/cychester/p/9478616.html
Copyright © 2020-2023  润新知