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;
}

 

posted @ 2013-05-15 14:02  痴人指路  阅读(390)  评论(0编辑  收藏  举报