题解:UVA141 The Spot Game
浅发一波双哈希题解
#include <iostream>
#include <set> // 集合容器库,用于存储哈希值
#include <utility> // 工具库,包含pair等
using namespace std;
typedef unsigned long long ull;
// 定义两个不同的哈希基数,用于双哈希减少冲突概率
const ull base1 = 131;
const ull base2 = 13131;
const int MAX_N = 50;
/*
* 计算棋盘状态的哈希值(使用双哈希技术)
* @param board 棋盘状态数组
* @param rot 旋转角度(0:0°, 90:90°, 180:180°, 270:270°)
* @param n 棋盘实际尺寸
* @return 包含两个哈希值的pair
*/
pair<ull, ull> compute_hash(int board[MAX_N][MAX_N], int rot, int n) {
ull hash1 = 0;
ull hash2 = 0;
// 根据旋转角度计算哈希值
if (rot == 0) { // 0°旋转(原始状态)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int val = board[i][j]; // 获取棋盘当前位置的值
hash1 = hash1 * base1 + val; // 更新第一个哈希值
hash2 = hash2 * base2 + val; // 更新第二个哈希值
}
}
}
else if (rot == 90) { // 90°顺时针旋转
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// 计算旋转后的坐标
int x = n - 1 - j;
int y = i;
int val = board[x][y];
hash1 = hash1 * base1 + val;
hash2 = hash2 * base2 + val;
}
}
}
else if (rot == 180) { // 180°旋转
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// 计算旋转后的坐标
int x = n - 1 - i;
int y = n - 1 - j;
int val = board[x][y];
hash1 = hash1 * base1 + val;
hash2 = hash2 * base2 + val;
}
}
}
else if (rot == 270) { // 270°顺时针旋转(或90°逆时针)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// 计算旋转后的坐标
int x = j;
int y = n - 1 - i;
int val = board[x][y];
hash1 = hash1 * base1 + val;
hash2 = hash2 * base2 + val;
}
}
}
return make_pair(hash1, hash2); // 返回双哈希值
}
int main() {
int n;
while (cin >> n && n != 0) { // 读取输入直到遇到0
int moves[MAX_N*2][3];
for (int i = 0; i < 2 * n; i++) {
int x, y;
char op;
cin >> x >> y >> op;
// 转换为0-based索引并存储
moves[i][0] = x - 1; // x坐标(转换为0-based)
moves[i][1] = y - 1; // y坐标(转换为0-based)
moves[i][2] = (op == '+') ? 1 : 0; // 操作类型:1表示放置,0表示移除
}
int board[MAX_N][MAX_N] = {0}; // 初始化棋盘,全部置0
set<pair<ull, ull>> seen; // 存储已见过的哈希值集合
bool found = false; // 标记是否已找到获胜者
// 处理每一步操作
for (int step = 0; step < 2 * n; step++) {
// 获取当前操作
int x = moves[step][0];
int y = moves[step][1];
int op = moves[step][2];
// 执行操作:放置或移除棋子
board[x][y] = op;
// 计算当前状态及其旋转状态的哈希值
pair<ull, ull> hashes[4];
hashes[0] = compute_hash(board, 0, n); // 原始状态
hashes[1] = compute_hash(board, 90, n); // 90°旋转
hashes[2] = compute_hash(board, 180, n); // 180°旋转
hashes[3] = compute_hash(board, 270, n); // 270°旋转
// 检查是否有重复状态
bool duplicate = false;
for (int i = 0; i < 4; i++) {
if (seen.find(hashes[i]) != seen.end()) {
duplicate = true;
break;
}
}
// 如果发现重复状态
if (duplicate) {
// 确定当前玩家(奇数步为玩家1,偶数步为玩家2)
int player = (step % 2 == 0) ? 1 : 2;
// 获胜者为对方玩家
int winner = (player == 1) ? 2 : 1;
// 输出结果
cout << "Player " << winner << " wins on move " << step + 1 << '\n';
found = true;
break; // 游戏结束,跳出循环
}
else {
// 如果没有重复,将四个旋转状态的哈希值都存入集合
for (int i = 0; i < 4; i++) {
seen.insert(hashes[i]);
}
}
}
// 如果所有操作处理完都没有重复状态
if (!found) {
cout << "Draw\n"; // 输出平局
}
}
return 0;
}
对于每个游戏,执行