【棋子翻转问题】

问题:

在一个长方形的 4x4 场地上摆放了 16 个正方形的双面棋子。每个棋子的一面是
白色的,另一面是黑色的。每一轮你可以翻转 3 到 5 块,从而将其上侧的颜色从黑色变为
白色,反之亦然。每轮都会根据以下规则选择要翻转的棋子:
(1)选择 16 个棋子中的任意一个。
(2)将该棋子以及相邻的上、下、左、右的棋子反转。
比如下面左边的棋盘,以右边的字符串来表示,其中 b 表示该棋子黑色朝上,w 表示
该棋子白色朝上。
请设计算法采用最少的步骤使整个棋盘上的棋子全部变白或者变黑。
输入要求:
输入由 4 行组成,每行有 4 个字符“w”或“b”,表示棋盘上棋子的颜色。
输出要求:
在输出一个整数,也就是从某个位置开始使棋盘所有棋子变白或者变黑所需的最小步骤。
如果刚开始就满足条件,则输出 0;如果不可能实现目标,则输出-1。
样例输入:
bwwb
bbwb
bwwb
bwww
样例输出:
4
 

思路:

二进制蛮力法

 

代码:

#include<bits/stdc++.h>
using namespace std;
 
#define n 4
 
int digits;
int chess[10010][10010];
int work[10010][10010];
 
void turn(int i, int j)
{
    work[i][j] = !work[i][j];
    if(i-1 >= 0) work[i-1][j] = !work[i-1][j];
    if(j-1 >= 0) work[i][j-1] = !work[i][j-1];
    if(i+1 <= n) work[i+1][j] = !work[i+1][j];
    if(j+1 <= n) work[i][j+1] = !work[i][j+1];
 
    return;
}
int handle1(int way)
{
    int cnt = 0;
    int i = 0, j = 0;
 
    for(int k = 0; k < digits; k++)
    {
        if(way & (1 << k))
        {
            cnt++;
            i = k / n;
            j = k % n;
            turn(i, j);
        }
    }
 
    for(int ii = 0; ii < n; ii++)
    {
        for(int jj = 0; jj < n; jj++)
        {
            if(work[ii][jj] != 0) return -1;
        }
    }
    return cnt;
}
 
int handle0(int way)
{
    int cnt = 0;
    int i = 0, j = 0;
 
    for(int k = 0; k < digits; k++)
    {
        if((~way) & (1 << k))
        {
            cnt++;
            i = k / n;
            j = k % n;
            turn(i, j);
        }
    }
 
    for(int ii = 0; ii < n; ii++)
    {
        for(int jj = 0; jj < n; jj++)
        {
            if(work[ii][jj] != 1) return -1;
        }
    }
    return cnt;
}
 
void back()
{
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            work[i][j] = chess[i][j];
        }
    }
}
 
int main()
{
    digits = n * n;
 
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            char c;
            cin >> c;
 
            chess[i][j] = (c == 'w' ? 0 : 1);
            work[i][j] = chess[i][j];
        }
    }
 
    int least = INT_MAX;
    int steps;
    for(int way = 0; way < (1 << digits); way++)
    {
        steps = handle1(way);
        if(steps != -1)
        {
            if(steps < least) least = steps;
        }
        back();
        steps = handle0(way);
        if(steps != -1)
        {
            if(steps < least) least = steps;
        }
        back();
    }
 
    if(least == INT_MAX) least = -1;
 
    cout << least << endl;
 
    return 0;
}

 

回溯法代码:

#include <iostream>
#include <vector>
using namespace std;

const int maxn = 15;
vector<vector<char>> grid(maxn, vector<char>(maxn, 'b'));
int n;
void change(int x, int y){
    int dx[] = {0, 0, -1, 1, 0};
    int dy[] = {-1, 1, 0, 0, 0};
    for(int i = 0; i < 5; i++){
        int nx = x + dx[i];
        int ny = y + dy[i];
        if(grid[nx][ny] == 'b'){
            grid[nx][ny] = 'w';
        }
        else{
            grid[nx][ny] = 'b';
        }
    }

}
bool dfs(int x, char c){    //迭代加深搜索,每次最多搜索x层
    if(x == 0){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(grid[i][j] != grid[1][1]) return false;
            }
        }
        return true;
    }
    
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(grid[i][j] == c){
                change(i, j);   //注意:该代码未实现查重
                if(dfs(x - 1, c)) return true;
                change(i, j);   //再change一次完成撤销操作
            }
        }
    }
    return false;
}
int main(){

    cin >> n;

    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> grid[i][j];
        }
    }

    int cntbtow = 0, cntwtob = 0;
    for(int i = 0; i <= 10; i++){
        if(dfs(i, 'b')){
            cntbtow = i;
            break;
        }
        if(dfs(i, 'w')){
            cntwtob = i;
            break;
        }

    }

    if(cntbtow || cntwtob)
    {
        int result;
        if(cntbtow && cntwtob) result = min(cntbtow, cntwtob);
        else result = max(cntbtow, cntwtob);

        cout << result << endl;
        return 0;
    }
    cout << -1 << endl;
    
    return 0;
}

 

 

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的黑白棋子翻转程序的 C 语言代码: ``` #include <stdio.h> #define SIZE 8 void print_board(int board[][SIZE]) { printf(" "); for (int i = 0; i < SIZE; i++) { printf("%d ", i); } printf("\n"); for (int i = 0; i < SIZE; i++) { printf("%d ", i); for (int j = 0; j < SIZE; j++) { printf("%c ", board[i][j] == 1 ? 'X' : board[i][j] == 2 ? 'O' : '-'); } printf("\n"); } } void flip_pieces(int board[][SIZE], int row, int col, int player) { int opponent = player == 1 ? 2 : 1; int dr, dc; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) { continue; } for (int k = 1; k < SIZE; k++) { dr = row + k * i; dc = col + k * j; if (dr < 0 || dr >= SIZE || dc < 0 || dc >= SIZE) { break; } if (board[dr][dc] == 0) { break; } if (board[dr][dc] == player) { for (int l = 1; l < k; l++) { board[row + l * i][col + l * j] = player; } break; } } } } } int main() { int board[SIZE][SIZE] = {0}; board[3][3] = board[4][4] = 1; board[3][4] = board[4][3] = 2; int player = 1; int row, col; while (1) { print_board(board); printf("Player %d's turn.\n", player); printf("Enter row and column (e.g. 3 4): "); scanf("%d %d", &row, &col); if (row < 0 || row >= SIZE || col < 0 || col >= SIZE) { printf("Invalid input.\n"); continue; } if (board[row][col] != 0) { printf("That square is already occupied.\n"); continue; } board[row][col] = player; flip_pieces(board, row, col, player); player = player == 1 ? 2 : 1; } return 0; } ``` 这个程序实现了一个简单的黑白棋子翻转游戏,玩家可以通过输入行和列来下棋,程序会自动翻转对手的棋子
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值