博弈——Treblecross

本文介绍了一款名为Treblecross的游戏,该游戏的目标是在一维棋盘上连成三个X以获胜。文章详细分析了游戏策略,包括如何通过最优玩法确保胜利,并提供了具体的示例和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Treblecross is a two player game where the goal is to get three X in a row on a one-dimensional board. At the start of the game all cells in the board are empty. In each turn a player puts an X in an empty cell, and if the move results three X next to each other, that player wins.

Given the current state of the game, you are to determine if the current player to move can win the game assuming both players play optimally.

Consider the game where the board size is 5 cells. If the first player puts an X at position three (in the middle) so the state becomes ..X.., he will win the game as no matter where the other player puts his X, the first player can get three X in a row. If, on the other hand, the first player puts the X in any other position, the second player will win the game by putting the X in the opposite corner (for instance, after the second players move the state might be .X..X). This will force the first player to put an X in a position so the second player wins in the next move.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing a string denoting the current status of the game. The string will only contain the characters '.' and 'X'. The length of the string (the size of the board) will be between 3 and 200 characters, inclusive. No state will contain three X in a row.

Output

For each case, print the case number and the positions on the board, where the player to move may put an X and win the game. The positions should be separated by a single space, and be in increasing order. The leftmost position on the board is 1. If there is no such position print 0.

Sample Input

4

.....

X.....X..X.......X....X..X

.X.X...X

..................

Sample Output

Case 1: 3

Case 2: 0

Case 3: 3

Case 4: 5 6 13 14


题意:

给一个字符串,两人轮流把'.'换成'X',谁先使局面变成三个连续的'X'谁赢 ,如果存在赢的走法,输出所有赢的走法的第一步,如果必输输出0

思路:

很明显一个'X'的左边两个格子和右边两个格子都是不能下的,否则对手会赢。那么将这个字符串分区来异或各区间的sg值即可


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=220;
int sg[maxn];
int pos;
int n;
char s[maxn];
int ans[maxn];
bool win()     //判断当前局势是否已经出现三个连续'X'
{
    for(int i=0; i<n-2; i++)
         if(s[i]=='X'&&s[i+1]=='X'&&s[i+2]=='X')
            return true;
    return false;
}
int getsg(int x)
{
    if(sg[x]!=-1)
        return sg[x];
    if(x==0)
        return sg[x]=0;
    bool vis[maxn]={false};
    for(int i=1; i<=x; i++)
        vis[getsg(max(0, i-3))^getsg(max(0, x-i-2))]=true;  //如果在连续x个空格子里放一个'X'那么其左右两边各两个格子都不能放'X'
    for(int i=0; ; i++)
        if(!vis[i])
            return sg[x]=i;
}
bool towin()
{
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X')
            continue;
        s[i]='X';
        if(win())   //如果对手可以赢
        {
            s[i]='.';
            return false;
        }
        s[i]='.';
    }
    int tag=0;
    int cnt=0;
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X'||(i>=1&&s[i-1]=='X')||(i>=2&&s[i-2]=='X')||(i+1<n&&s[i+1]=='X')||(i+2<n&&s[i+2]=='X')) //判断这个格子是否能走
        {
            tag^=getsg(cnt);
            cnt=0;
        }
        else
            cnt++;
    }
    tag^=getsg(cnt);
    return tag==0;
}
void solve()
{
    pos=0;
    scanf("%s", s);
    n=strlen(s);
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X')
            continue;
        s[i]='X';  //如果这一个不是'X',将这一格变成'X'看是否会赢
        if(win()||towin())    //如果能赢,就存下来
            ans[pos++]=i+1;
        s[i]='.';      //还原
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    for(int cas=1; cas<=t; cas++)
    {
        memset(sg, -1, sizeof(sg));
        solve();
        if(pos==0)
            printf("Case %d: 0\n", cas);
        else
        {
            printf("Case %d: %d", cas, ans[0]);
            for(int i=1; i<pos; i++)
                printf(" %d", ans[i]);
            printf("\n");
        }
    }
    return 0;
}







马步将军问题(也称为骑士巡逻问题)是一个经典的组合数学问题,它要求找到一个马在棋盘上移动的路径,使得马能够按照国际象棋中马的移动规则访问棋盘上的每一个方格恰好一次。这是一个回溯算法的典型应用。 以下是使用Python语言编写的一个简单的马步将军问题解决方案的示例代码。此代码尝试找到一个马在8x8国际象棋棋盘上的一条路径,并打印出马的移动序列。请注意,这个问题的解决方案并不是唯一的,并且在不同大小的棋盘上可能没有解。 ```python # 定义8x8棋盘的移动增量 N = 8 move_x = [2, 1, -1, -2, -2, -1, 1, 2] move_y = [1, 2, 2, 1, -1, -2, -2, -1] # 初始化棋盘 def solve_kt(n): # 创建棋盘并初始化 sol = [[-1 for i in range(n)] for j in range(n)] # 马的第一个位置 x = 0 y = 0 sol[x][y] = 0 # 马的移动列表 move序号 = [0] # 从第一个位置开始,尝试所有可能的移动 if not solveKTUtil(n, x, y, move序号, move_x, move_y, sol): print("没有解决方案") else: print_solution(sol) # 递归函数来解决骑士巡逻问题 def solveKTUtil(n, curr_x, curr_y, move序号, move_x, move_y, sol): # 如果我们已经找到了N*N-1个移动,则成功 if move序号[0] == n*n: return True # 尝试所有下一个可能的移动 for i in range(8): next_x = curr_x + move_x[i] next_y = curr_y + move_y[i] if isSafe(next_x, next_y, sol, n): sol[next_x][next_y] = move序号[0] move序号[0] += 1 if solveKTUtil(n, next_x, next_y, move序号, move_x, move_y, sol): return True # 回溯 sol[next_x][next_y] = -1 move序号[0] -= 1 return False # 检查新位置是否是一个有效的未访问位置 def isSafe(x, y, sol, n): if x >= 0 and x < n and y >= 0 and y < n and sol[x][y] == -1: return True return False # 打印解决方案 def print_solution(sol): for i in range(N): for j in range(N): print(f"{sol[i][j]:2}", end=" ") print() # 主函数 def main(): solve_kt(N) if __name__ == "__main__": main() ``` 请注意,运行上述代码可能需要一些时间,因为它尝试了棋盘上所有可能的移动,并使用回溯法找到解决方案。回溯法是一种尝试方法,它逐步构建解决方案,并在发现当前构建的部分不可能导致最终解决方案时取消之前的部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值