5.22~~Click-o-Mania
题目来源:
https://www.hackerrank.com/rest/contests/monthly/challenges/click-o-mania/hackers/kdavis215/download_solution
#include <stdio.h> #include <string.h> #include <math.h> #include <vector> #include <queue> #include <set> #include <stdlib.h> #include <time.h> #include <iostream> #define WIDTH 10 #define HEIGHT 20 #define MAX_SET_SIZE 100 #define SIZE WIDTH*HEIGHT #define EMPTY '-' #define DEPTH 2 #define TRIALS 1000 using namespace std; int find_set(int grid[SIZE], int i) { int p = i; vector<int> path; while (grid[p] >= 0) { path.push_back(p); p = grid[p]; } // Compress path for(vector<int>::iterator it = path.begin(); it != path.end(); ++it) { grid[*it] = p; } return p; } int to_index(int x, int y) { return y * WIDTH + x; } void union_set(int grid[SIZE], int i, int j) { int a = find_set(grid, i); int b = find_set(grid, j); if (a != b) { if (-grid[a] > -grid[b]) { grid[a] += grid[b]; grid[b] = a; } else { grid[b] += grid[a]; grid[a] = b; } } } class State { public: int block_count; int k; char (*board)[WIDTH]; int groups[SIZE]; State(char[HEIGHT][WIDTH]); void find_groups(); void display_board(); void display_groups(); void fall_down(); void remove_column(int); void shift_left(); void calculate_k(); int score(); int recursive_score(int); int pick_move(); int pick_move2(); int play_random_game(); State* make_move(int); ~State(); }; State::State(char grid[HEIGHT][WIDTH]) { board = new char[HEIGHT][WIDTH]; for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { board[y][x] = grid[y][x]; } } for (int i = 0; i < SIZE; i++) { this->groups[i] = -1; } block_count = 0; k = 0; fall_down(); shift_left(); find_groups(); } State::~State() { delete[] board; } void State::find_groups() { for(int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { char v = board[y][x]; if (v != EMPTY) { if (x - 1 >= 0) { if (v == board[y][x - 1]) { union_set(groups, to_index(x, y), to_index(x - 1, y)); } } if (x < WIDTH - 1) { if (v == board[y][x + 1]) { union_set(groups, to_index(x, y), to_index(x + 1, y)); } } if (y - 1 >= 0) { if (v == board[y - 1][x]) { union_set(groups, to_index(x, y), to_index(x, y - 1)); } } if (y < HEIGHT - 1) { if (v == board[y + 1][x]) { union_set(groups, to_index(x, y), to_index(x, y + 1)); } } } else { groups[to_index(x, y)] = -1; } } } } void State::fall_down() { for (int x = 0; x < WIDTH; x++) { int i = HEIGHT - 1; for (int y = HEIGHT - 1; y >= 0; y--) { if (board[y][x] != EMPTY) { char temp = board[i][x]; board[i][x] = board[y][x]; board[y][x] = temp; --i; } } } } void State::remove_column(int x) { for (int i = x; i < WIDTH - 1; i++) { for (int y = 0; y < HEIGHT; y++) { board[y][i] = board[y][i + 1]; } } for (int y = 0; y < HEIGHT; y++) { board[y][WIDTH - 1] = EMPTY; } } void State::shift_left() { for (int x = 0; x < WIDTH; x++) { bool e = true; for (int y = 0; y < HEIGHT; y++) { if (board[y][x] != EMPTY) { e = false; break; } } if (e) { remove_column(x); } } } void State::display_board() { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { cerr << board[y][x] << " "; } cerr << "\n"; } } void State::display_groups() { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { cerr << find_set(groups, to_index(x, y)) << " "; } cerr << "\n"; } } int State::pick_move2() { clock_t t1,t2; t1=clock(); //code goes here int trials = 0; int best = -1000; int best_move = 0; vector<int> possible_moves; for (int i = 0; i < SIZE; i++) { if (groups[i] < -1) { possible_moves.push_back(i); } } if (possible_moves.size() == 0) { return score(); } float diff = 0; float limit = 2.8f * CLOCKS_PER_SEC; while (diff < limit) { ++trials; int i = rand() % possible_moves.size(); int move = possible_moves[i]; State* s = make_move(move); int score = s->play_random_game(); delete s; if (score > best) { best = score; best_move = move; } t2=clock(); diff = ((float)t2-(float)t1); } cerr << "TRIALS: " << trials; return best_move; } int State::pick_move() { int best = -1000; int best_move = 0; for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { int i = to_index(x, y); if (groups[i] < -1) { State *n = make_move(i); int s = n->recursive_score(DEPTH); cerr << i << ": " << s << endl; if (s > best) { best = s; best_move = i; } delete n; } } } return best_move; } int State::recursive_score(int depth) { if (depth == 0) { return score(); } int best = -1000; bool blocks_remaining = false; for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { int i = to_index(x, y); if (groups[i] < -1) { blocks_remaining = true; State *n = make_move(i); int s = n->recursive_score(depth - 1); s = (s << 8) - groups[i]; best = s > best ? s : best; delete n; } } } if (!blocks_remaining) { return score(); } return best; } int State::play_random_game() { vector<int> possible_moves; for (int i = 0; i < SIZE; i++) { if (groups[i] < -1) { possible_moves.push_back(i); } } if (possible_moves.size() == 0) { calculate_k(); if (block_count == 0) { return 100000; } return 0; } int i = rand() % possible_moves.size(); int move = possible_moves[i]; State* s = make_move(move); int score = s->play_random_game(); delete s; return 1 + score; } int State::score() { calculate_k(); return (1 - block_count) / 20; } void State::calculate_k() { set<char> s; block_count = 0; for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { char v = board[y][x]; if (v != EMPTY) { s.insert(v); block_count++; } } } k = s.size(); } State* State::make_move(int index) { queue<int> q; q.push(index); char new_board[HEIGHT][WIDTH]; for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { new_board[y][x] = board[y][x]; } } char v = new_board[index / WIDTH][index % WIDTH]; while (!q.empty()) { int i = q.front(); q.pop(); int x = i % WIDTH; int y = i / WIDTH; new_board[y][x] = EMPTY; if (x - 1 >= 0) { if (v == new_board[y][x - 1]) { q.push(to_index(x - 1, y)); } } if (x < WIDTH - 1) { if (v == new_board[y][x + 1]) { q.push(to_index(x + 1, y)); } } if (y - 1 >= 0) { if (v == new_board[y - 1][x]) { q.push(to_index(x, y - 1)); } } if (y < HEIGHT - 1) { if (v == new_board[y + 1][x]) { q.push(to_index(x, y + 1)); } } } return new State(new_board); } int main() { srand (time(NULL)); int x, y, k; scanf("%d %d %d", &x, &y, &k); char grid[HEIGHT][WIDTH]; for( int i=0; i<x; i++) { scanf("%s[^\\n]%*c", grid[i]); } State s = State(grid); int i = s.pick_move2(); int mx = i % WIDTH; int my = i / WIDTH; cout << my << " " << mx << "\n"; return 0; }