poj1753Flip Game之 广搜解法+暴搜解法

来源:互联网 发布:python 登录界面 编辑:程序博客网 时间:2024/05/20 09:07

题意:每次翻一个棋子会带动周围棋子翻面,问需要的最小翻棋次数使得棋盘颜色一致。

分析:棋盘上有16个棋子,分别对应二进制数的16-1位,用1表示black或white,这样一个整数value就可以表示一种棋盘状态。

每次翻棋可以用异或^进行,然后在value的基础上进行搜索。

/*输入方式一*/// int k = 0;// for (int i = 0; i < 4; ++i){//     for (int j = 0; j < 4; ++j){//         cin >> atlas[i][j];//         if(atlas[i][j] == 'b') value += 1<<k;//         k++;//     }// }/*输入方式二*/// for (int i = 0; i < 4; ++i){//     for (int j = 0; j < 4; ++j){//         cin >> atlas[i][j];//         value <<= 1;//         if(atlas[i][j] == 'b') value += 1;//     }// }/*输入方式三*/// for (int i = 0; i < 16; ++i)// {//     char c;//     cin >> c;//     if(c == 'b') value += judge[i];// }

解法一:暴力搜索

/**********************************暴力搜索法每个棋子要么翻要么不翻,总共有2^16 = 65536种可能性;假设每一位用1表示翻棋,则可以用0-65535表示这65536种可能性;遍历所有翻棋方法,找到使当前棋局变为全白或全黑的方法并保存步数;找到其中最小步数。 **********************************/#include <cstdio>  #include <iostream>  using namespace std;  char atlas[5][5];//1表示黑棋int change[20] = {    0xc800,0xe400,0x7200,0x3100,    0x8c80,0x4e40,0x2720,0x1310,    0x08c8,0x04e4,0x0272,0x0131,    0x008c,0x004e,0x0027,0x0013};int judge[20] = {    0x8000,0x4000,0x2000,0x1000,    0x0800,0x0400,0x0200,0x0100,    0x0080,0x0040,0x0020,0x0010,    0x0008,0x0004,0x0002,0x0001};int value;int step;int main()  {      value = 0;    step = 17;    int k = 0;    for (int i = 0; i < 4; ++i){        for (int j = 0; j < 4; ++j){            cin >> atlas[i][j];            if(atlas[i][j] == 'b') value += 1<<k;            k++;        }    }    for (int i = 0; i < 65536; ++i) {//65536种翻棋方法        int tvalue = value;        int tstep = 0;        for (int j = 0; j < 16; ++j){//依次判断16个棋子是否翻动            if (i & judge[j]){                tvalue ^= change[j];                tstep++;            }        }        if (tvalue == 0 || tvalue == 65535) step = min(step,tstep);    }    if(step < 17) cout << step << endl;    else cout << "Impossible" << endl;    return 0;  }  


解法二:宽度优先搜索

/**********************************广度优先搜索首先进行棋盘的状态压缩,保存棋盘;然后对棋盘进行广度优先搜索;要注意,广搜入口有16个,但是由于翻棋顺序对于棋盘结果不影响,所以翻棋状态只有2^16 = 65536种。 **********************************/#include <iostream>  #include <cstring>#include <queue>  using namespace std;  int change[20] = {//16个翻棋方式    0xc800,0xe400,0x7200,0x3100,    0x8c80,0x4e40,0x2720,0x1310,    0x08c8,0x04e4,0x0272,0x0131,    0x008c,0x004e,0x0027,0x0013};int value;int step;int visit[65536];typedef pair<int,int> p;queue <p> qu;void bfs(){    while(!qu.empty()){        p f = qu.front();qu.pop();        for (int i = 0; i < 16; ++i){            int tf = f.first^change[i];            int tstep = f.second + 1;            if(visit[tf]) continue;            if(tf == 0 || tf == 65535){                step = tstep;return;            }            visit[tf] = 1;            qu.push(make_pair(tf,tstep));        }    }}int main()  {      value = 0;    step = 17;    for (int i = 0; i < 4; ++i){        for (int j = 0; j < 4; ++j){            char c;            cin >> c;            value <<= 1;            if(c == 'b') value += 1;        }    }    if(value == 0 || value == 65535) {        cout << "0" << endl;return 0;    }    qu.push(make_pair(value,0));    memset(visit,0,sizeof(visit));    visit[value] = 1;    bfs();    if(step < 17) cout << step << endl;    else cout << "Impossible" << endl;    return 0;  }