开始的时候自己读完题目,知道它的目的,但是如何做,脑子里还没有一个清晰的思路。因为某种原因,我直接网上搜了别人的思路,知道了题目的思路,下午边上课边写程序,发现原来是这么简单的题目。下面是给我启发的那篇文章:
转载自:
题目:
Flip Game题目大意是在一个4*4的棋盘上翻转棋子,翻转了一个棋子以后,他的上下左右四个方向的棋子都得跟着变色,最后使得棋盘上所有的棋子都是白色,或者都是黑色。统计要翻转的棋子的个数。分析:
1. 棋子只有黑白两色,因此如果翻转同一个棋子不能超过一次。因为翻转两次就等于没有翻。
2. 相同棋子之间的翻转顺序是不会影响最终翻转的结果的。
那么上面有16个棋子,也就是16个棋子处于两种状态,需要翻转,不需要翻转,总共有2^16次方种方案。因此采用枚举的方法就可以了。
数据结构:我们用位表示一个格子,那么4位组成一个16进制数,表示一行。用相应的位^1表示翻转,可以提前算出16种翻转的状态。如下:
- const int state[16] = {0xC800, 0xE400, 0x7200, 0x3100,
- 0x8C80, 0x4E40, 0x2720, 0x1310,
- 0x08C8, 0X04E4, 0X0272, 0X0131,
- 0X008C, 0X004E, 0X0027, 0X0013};
- //搜索采用回溯策略
-
- #include <stdio.h>
- #define ONLINE
- void online()
- {
- #ifdef ONLINE
- #else
- freopen("1753.in", "r", stdin);
- freopen("1753.out","w", stdout);
- #endif
- }
- int map = 0;
- const int END1 = 0x0000;
- const int END2 = 0xFFFF;
- const int state[16] = {0xC800, 0xE400, 0x7200, 0x3100,
- 0x8C80, 0x4E40, 0x2720, 0x1310,
- 0x08C8, 0X04E4, 0X0272, 0X0131,
- 0X008C, 0X004E, 0X0027, 0X0013};
- int result = 17;
- void read()
- {
- char c;
- for (int i=0; i < 16; i ++)
- {
- c = getchar();
- //scanf("%c", &c);
- if (c == 'b')
- {
- map = map << 1;
- map =(map^1);
- }
- else if(c=='w')
- {
- map = map<<1;
- }
- else
- i --;
- }
- }
- void search( int idx, int step)
- {
- if (step >= result)
- {
- return;
- }
- if (idx >= 16)
- {
- if (map == END2 || map == END1)
- {
- if (step < result)
- {
- result = step;
- }//end if step
- }//end if map
- return;
- }
- search(idx+1, step);
- map = map ^ state[idx];
- search(idx+1, step+1);
- map = map^state[idx];
- return;
- }
- void print()
- {
- if (result >= 17)
- {
- printf("Impossible");
- }
- else
- printf("%d",result);
- }
- int main()
- {
- online();
- read();
- search(0, 0);
- print();
- return 0;
- }
通过此题呢,我学到了用位存储信息,以前苏哥给我讲用位做八皇后,当时觉得很巧妙,但是自己没有吸收。
今天做了这道题,进一步发现了位存储矩阵信息的优点,不仅节省空间,还节省时间。妙~
一时兴起,还根据这个小算法做了一个小程序【360vsQQ】,很久没碰MFC了、这次的代码除了算法部分、其他的基本都是copy的以前写的【残缺棋盘】程序:
//主界面
//解
//说明书