(比赛)B - 棋盘问题(dfs)

本文介绍了一种通过深度优先搜索解决特定棋盘问题的方法。该问题要求在给定形状的棋盘上放置一定数量的棋子,使得任意两棋子不在同一行或列。文章提供了一个C++实现示例,并解释了核心算法。

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

B - 棋盘问题

Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%lld & %llu

Practice POJ 1321

Description

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

Input

输入含有多组测试数据。 
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 
当为-1 -1时表示输入结束。 
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。 

Output

对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

Sample Output

2 1

 

//dfs 逐行放置,有点难啊

 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;
 4 
 5 char map[9][9];
 6 //int hang[9];
 7 int lie[9];
 8 int all;
 9 int n,m;
10 int k;
11 
12 void dfs(int cur)
13 {
14     int i,j;
15     if (k==m)
16     {
17         all++;
18         return;
19     }
20     for (i=cur;i<=n;i++)
21     {
22         for (j=1;j<=n;j++)
23         {
24             if (map[i][j]=='#' && lie[j]==0)//如果可以放
25             {
26                 lie[j]=j;
27                 k++;
28                 dfs(i+1);
29                 k--;
30                 lie[j]=0;
31             }
32         }
33     }
34 }
35 
36 int main ()
37 {
38     int i,j;
39     while (cin>>n>>m)
40     {
41         if (n==-1&&m==-1) break;
42         all=0;
43         k=0;
44         //memset(hang,0,sizeof(hang));
45         memset(lie,0,sizeof(lie));
46         for (i=1;i<=n;i++)
47         {
48             for (j=1;j<=n;j++)
49             cin>>map[i][j];
50         }
51         dfs(1);
52         cout<<all<<endl;;
53     }
54     return 0;
55 }
View Code

 

转载于:https://www.cnblogs.com/haoabcd2010/p/5776716.html

"在五子棋的对弈中,友谊的小船说翻就翻?" 不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着"友谊第一,比赛第二"的宗旨,决定在一块 5×5 的棋盘上,用黑白两色的棋子来决出胜负。但他们又都不忍心让对方失落,于是决定用一场和棋(平局)作为彼此友谊的见证。 比赛遵循以下规则: 1. 棋盘规模:比赛在一个 5×5的方格棋盘上进行,共有 25 个格子供下棋使用。 2. 棋子类型:两种棋子,黑棋与白棋,代表双方。小蓝持白棋,小桥持黑棋。 3. 先手规则:白棋(小蓝)具有先手优势,即在棋盘空白时率先落子(下棋)。 4. 轮流落子:玩家们交替在棋盘上放置各自的棋子,每次仅放置一枚。 5. 胜利条件:率先在横线、竖线或斜线上形成连续的五个同色棋子的一方获胜。 6. 平局条件:当所有 25 个棋盘格都被下满棋子,而未决出胜负时,游戏以平局告终。 在这一设定下,小蓝和小桥想知道,有多少种不同的棋局情况,既确保棋盘下满又保证比赛结果为平局。 # 五子棋 # 定义二维数组 mp = [[0] * 5 for i in range(5)] ans = 0 def check(): global ans # 检查是否胜利 for i in range(5): if sum(mp[i]) % 5 == 0: return for j in range(5): if sum(mp[i][j] for i in range(5)) % 5 == 0: # 这里应该是mp[i][j]而不是mp[i] return # 主对角线 if sum(mp[i][i] for i in range(5)) % 5 == 0: return # 副对角线 if sum(mp[i][4 - i] for i in range(5)) % 5 == 0: return # 如果没有胜利,答案加一 ans += 1 def dfs(num, ones): # 传入白棋的数量 if ones > 13: # 剪枝 return if num == 25: if ones == 13: check() return x = num // 5 y = num % 5 mp[x][y] = 1 dfs(num + 1, ones + 1) mp[x][y] = 0 dfs(num + 1, ones) print(3126376) 给我解释一下dfs的运行过程,拿一种符合情况的例子举例
04-03
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define B_SIZE 19 #define M_MOVE 400 #define S_COUNT 5000 #define H_SIZE 100000 //S_COUNTz //H_SIZE=HAXI_SIZE哈希链表对棋局进行缓存, char board[B_SIZE][B_SIZE];//棋盘暂时用字符串生成 int h[M_MOVE][2];//记录每一步 int count = 0;//记录步数 int cp = 1;//cp=current_player int lx = -1; int ly = -1; int lc[B_SIZE][B_SIZE] = {0}; int end_flag = 0;//弃权次数,用于计算是否结束比赛 // 并查集初始化 int parent[B_SIZE * B_SIZE]; void u_find() { for (int i = 0; i < B_SIZE * B_SIZE; i++) { parent[i] = i; } } // 查找根节点 //路径压缩优化,提高查找效率 int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } // 合并两个集合,处理围棋里面的连通块,即大龙** void union_sets(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; } } //深度优先策略,搜索气 void dfs(int x, int y, char color, int visited[B_SIZE][B_SIZE], int *qi) { if (x < 0 || x >= B_SIZE || y < 0 || y >= B_SIZE) { return; } if (visited[x][y]) { return; } if (board[x][y] == '.') { (*qi)++; //更新气的数量 return; } if (board[x][y] != color) { return; } visited[x][y] = 1; dfs(x + 1, y, color, visited, qi); dfs(x - 1, y, color, visited, qi); dfs(x, y - 1, color, visited, qi); dfs(x, y + 1, color, visited, qi); } //记录气的数目 int qi[B_SIZE][B_SIZE]; //更新气的数目 void update_qi() { memset(qi, -1, sizeof(qi)); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j] != '.') { int visited[B_SIZE][B_SIZE] = {0}; int qis = 0; dfs(i, j, board[i][j], visited, &qis); qi[i][j] = qis; } } } } //初始化棋盘 void initialize() { for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { board[i][j] = '.'; } } count = 0; lx = -1; ly = -1; memset(lc, 0, sizeof(lc)); u_find(); update_qi(); end_flag = 0; } //显示棋盘 void show() { printf(" "); for (int i = 0; i < B_SIZE; i++) { printf(" %c ", 'a' + i); } printf("\n"); for (int i = 0; i < B_SIZE; i++) { printf("%2d", i + 1); for (int j = 0; j < B_SIZE; j++) { if (i == lx && j == ly) { printf("-%c-", board[i][j] == '*' ? '*' : board[i][j] == 'o' ? 'o' : '.'); } else { printf(" %c ", board[i][j]); } } printf("\n"); } } //检测合法落子 int legal_move(int x, int y) { return x >= 0 && x < B_SIZE && y >= 0 && y < B_SIZE; } //提子 int capture_zi(int x, int y) { char opponent = (cp == 1)? 'o' : '*'; int captured = 0; int visited[B_SIZE][B_SIZE] = {0}; int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int i = 0; i < 4; i++) { int new_x = x + directions[i][0]; int new_y = y + directions[i][1]; if ( legal_move(new_x, new_y) && board[new_x][new_y] == opponent && !visited[new_x][new_y]) { int liberties = 0; dfs(new_x, new_y, opponent, visited, &liberties); if (liberties == 0) { for (int j = 0; j < B_SIZE; j++) { for (int k = 0; k < B_SIZE; k++) { if (visited[j][k]) { board[j][k] = '.'; captured++; } } } } memset(visited, 0, sizeof(visited)); } } update_qi(); return captured; } //判断打劫 int is_ko(int x, int y) { if (count < 2) { return 0; } int captured = capture_zi(x, y); if (captured!= 1) return 0; int prev_x = h[count - 2][0]; int prev_y = h[count - 2][1]; int current[B_SIZE][B_SIZE] = {0}; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j]!= lc[i][j]) { current[i][j] = 1; } } } int single_capture = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (current[i][j]) { if (single_capture) return 0; single_capture = 1; } } } if (single_capture && x == prev_x && y == prev_y) return 1; return 0; } //落子 void move(int x, int y) { board[x][y] = cp == 1? '*' : 'o'; h[count][0] = x; h[count][1] = y; count++; lx = x; ly = y; int captured = capture_zi(x, y); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { lc[i][j] = board[i][j]; } } //检测落子的气 int self = 0; int visited[B_SIZE][B_SIZE] = {0}; dfs(x, y, board[x][y], visited, &self); if (self == 0) { board[x][y] = '.'; count--; printf("wrong position,please change a correct position.\n"); return; } cp = 3 - cp; update_qi(); end_flag = 0; } //保存棋局 void save(const char *filename) { FILE *file = fopen(filename, "w"); if (file == NULL) { printf("can't open file\n"); return; } for (int i = 0; i < count; i++) { fprintf(file, "%d %d\n", h[i][0], h[i][1]); } fclose(file); } //读取棋局 void load(const char *filename) { initialize(); FILE *file = fopen(filename, "r"); if (file == NULL) { printf("can't open file\n"); return; } int x, y; while (fscanf(file, "%d %d", &x, &y) == 2) { move(x, y); } fclose(file); } //复盘 void replay() { initialize(); int a = 0;//记录当前步骤 char input; while (1) { show();//先展示棋盘 printf("N show the next situation, L show the next situation ,Q break.\n"); scanf(" %c", &input); if (input == 'N' && a < count - 1) { a++; move(h[a][0], h[a][1]); } else if (input == 'L' && a > 0) { a--; initialize(); for (int i = 0; i <= a; i++) { move(h[i][0], h[i][1]); } } else if (input == 'Q') { break; } } } //数子 void m_count() { int black = 0, white = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (board[i][j] == '*') { black++; } else if (board[i][j] == 'o') { white++; } } } printf("Black: %d, White: %d\n", black, white); if (black > white) { printf("Black stones win!\n"); } else if (white > black) { printf("White stones win!\n"); } else { printf("It's a draw!\n"); } } // 检查是否结束比赛 int game_over() { if (end_flag >= 2) { printf("Both players have passed consecutively. Game over!\n"); m_count(); return 1; } return 0; } //节点定义,存储坐标 typedef struct wjt { int x, y; int wins; int visits; struct wjt *next; } wjt; wjt *hash_table[H_SIZE]; // 简单的哈希函数,提高搜索决策效率 unsigned int hash(char board[B_SIZE][B_SIZE]) { unsigned int hash_val = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { hash_val = (hash_val * 31 + board[i][j]) % H_SIZE; } } return hash_val; } // 在哈希表中查找节点 wjt *find_node(char board[B_SIZE][B_SIZE], int x, int y) { unsigned int hash_val = hash(board); wjt *current = hash_table[hash_val]; while (current != NULL) { if (current->x == x && current->y == y) { return current; } current = current->next; } return NULL; } // 插入新节点到哈希表 void insert_node(char board[B_SIZE][B_SIZE], int x, int y) { unsigned int hash_val = hash(board); wjt *new_node = (wjt *)malloc(sizeof(wjt)); new_node->x = x; new_node->y = y; new_node->wins = 0; new_node->visits = 0; new_node->next = hash_table[hash_val]; hash_table[hash_val] = new_node; } // 改进后的评估函数,考虑棋子的气和布局 int evaluate(char board[B_SIZE][B_SIZE], int cp) { int b_score = 0, w_score = 0; int i, j; for (i = 0; i < B_SIZE; i++) { for (j = 0; j < B_SIZE; j++) { if (board[i][j] == '*') { b_score += qi[i][j]; } else if (board[i][j] == 'o') { w_score += qi[i][j]; } } } if (cp == 1) { return b_score - w_score; } else { return w_score - b_score; } } // 蒙特卡罗模拟 int mct(char board[B_SIZE][B_SIZE], int cp) { char temp[B_SIZE][B_SIZE]; memcpy(temp, board, sizeof(temp)); int player = cp; int end_flag = 0; int local_count = 0; int local_history[M_MOVE][2]; while (1) { int valid_flag = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (legal_move(i, j)) { local_history[local_count][0] = i; local_history[local_count][1] = j; local_count++; temp[i][j] = player == 1? '*' : 'o'; int captured = 0; // 模拟提子 char opponent = (player == 1)? 'o' : '*'; int visited[B_SIZE][B_SIZE] = {0}; int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int k = 0; k < 4; k++) { int new_x = i + directions[k][0]; int new_y = j + directions[k][1]; if (new_x >= 0 && new_x < B_SIZE && new_y >= 0 && new_y < B_SIZE && temp[new_x][new_y] == opponent &&!visited[new_x][new_y]) { int liberties = 0; int temp_visited[B_SIZE][B_SIZE] = {0}; dfs(new_x, new_y, opponent, temp_visited, &liberties); if (liberties == 0) { for (int m = 0; m < B_SIZE; m++) { for (int n = 0; n < B_SIZE; n++) { if (temp_visited[m][n]) { temp[m][n] = '.'; captured++; } } } } } } // 检测落子的气 int self = 0; int self_visited[B_SIZE][B_SIZE] = {0}; dfs(i, j, temp[i][j], self_visited, &self); if (self == 0) { temp[i][j] = '.'; local_count--; } else { valid_flag = 1; end_flag = 0; break; } } } if (valid_flag) break; } if (!valid_flag) { end_flag++; player = 3 - player; if (end_flag >= 2) { break; } continue; } player = 3 - player; } int black = 0, white = 0; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (temp[i][j] == '*') { black++; } else if (temp[i][j] == 'o') { white++; } } } if (cp == 1 && black > white) { return 1; } else if (cp == 2 && white > black) { return 1; } return 0; } // 电脑落子函数 void computer_move(char board[B_SIZE][B_SIZE], int cp) { memset(hash_table, 0, sizeof(hash_table)); for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { if (legal_move(i, j)) { insert_node(board, i, j); } } } for (int k = 0; k < S_COUNT; k++) { for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { wjt *node = find_node(board, i, j); if (node != NULL) { char temp[B_SIZE][B_SIZE]; memcpy(temp, board, sizeof(temp)); temp[i][j] = cp == 1? '*' : 'o'; int result = mct(temp, cp); node->visits++; if (result == 1) { node->wins++; } } } } } int best_x = -1, best_y = -1; double best_score = -1; for (int i = 0; i < B_SIZE; i++) { for (int j = 0; j < B_SIZE; j++) { wjt *node = find_node(board, i, j); if (node != NULL) { // 结合模拟结果和当前棋局评估来计算得分 double simulation_score = (double)node->wins / node->visits; int evaluation_score = evaluate(board, cp); double combined_score = simulation_score * 0.6 + evaluation_score * 0.4; // 可调整权重 if (combined_score > best_score) { best_score = combined_score; best_x = i; best_y = j; } } } } if (best_x != -1 && best_y != -1) { move(best_x, best_y); } } // 释放哈希表中所有节点的内存 void free_hash_table() { for (int i = 0; i < H_SIZE; i++) { wjt *current = hash_table[i]; wjt *next; while (current != NULL) { next = current->next; free(current); current = next; } hash_table[i] = NULL; } } int main(int argc, char *argv[]) { int mode; printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("------Game mode: 1. Two players 2. Human vs Computer------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("-----------------------------------------------------------\n"); printf("Please select:"); scanf("%d", &mode); initialize(); int x, y; char col_str[2]; int row; while (1) { show(); printf("Current player: %s\n", cp == 1 ? "Black" : "White"); if (mode == 2 && cp == 2) { // computer_move(board, cp); } else { char input[10]; printf("Please enter the move position (e.g., c12) or 'P' to pass: "); scanf("%s", input); if (strcmp(input, "P") == 0) { end_flag++; cp = 3 - count; if (game_over()) { break; } continue; } sscanf(input, "%1s%d", col_str, &row); x = row - 1; y = col_str[0] - 'a'; if (legal_move(x, y)) { if (is_ko(x, y)) { printf("This move is a ko. It is prohibited. Please make a new move!\n"); continue; } move(x, y); } else { printf("The move position is invalid. Please enter a new position!\n"); } } if (game_over()) { break; } char c[10]; //存储指令 printf("Enter S to save the game, L to load the game, R to replay the game, other to continue: "); scanf("%s", c); if (strcmp(c, "S") == 0) { char file[100]; //文件名 printf("Please enter the file name to save: "); scanf("%s", file); save(file); } else if (strcmp(c, "L") == 0) { char file[100]; printf("Please enter the file name to load: "); scanf("%s", file); load(file); } else if (strcmp(c, "R") == 0) { replay(); } } free_hash_table(); return 0; } 修改代码
最新发布
05-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值