poj 1753

题目概述

给定一4*4棋盘,每个位置有棋子,棋子黑面或白面朝上,每次可选一棋子翻转,其上下左右一格的棋子同时翻转,问可否使所有棋子同色朝上,若可,求最少需选几个棋子

时限

1000ms/3000ms

输入

共4行,每行4个字符,b代表黑面朝上,w代表白面朝上

限制

没有限制

输出

若可以,输出一数,最少选定棋子数,否则输出字符串Impossible

样例输入

case 1:

bwwb
bbwb
bwwb
bwww

case 2:

wwww
wwww
wwww
wwww

case 3:

wwww
wwww
wwww
wwwb

case 4:

wbww
bbbw
wbww
wwww

样例输出

case 1:

4

case 2:

0

case 3:

Impossible

case 4:

1

讨论

广搜,而且需要二进制及其操作,赋予电脑整体思考的能力,将棋盘上每个位置视为一个二进制位,如此一共16位,一个short正好,不过为求方便,实际使用的是unsigned short,因为不会牵扯符号问题且两个边界值很好表示,0和USHRT_MAX,采用广搜以求最少次数,每次搜索将上一次的值记录下,便于最后链式统计次数
如果棋盘再大一些咋办?那就得用bitset了把,比直接用二进制差不少呢

题解状态

292K,0MS,C++,1093B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f  
#define MAXN 16
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-6

unsigned short B, marked[65536], opt[16] = { 0xc800,0xe400,0x7200,0x3100,0x8c80,0x4e40,0x2720,0x1310,0x08c8,0x04e4,0x0272,0x0131,0x008c,0x004e,0x0027,0x0013 };//Bytes 以双字节存放棋盘原始数据 marked 存放广搜时上一次的B值 operator 棋盘上可行的16种翻转操作 以十六进制表示 用win7的计算器可以很方便算出
queue<unsigned short>q;//广搜辅助队列
int bfs(unsigned short B)//广搜 返回值是次数 不可能返回-1
{
    q.push(B);
    while (!q.empty()) {
        B = q.front();
        q.pop();
        if (!B || B == USHRT_MAX) {//分别代表全白和全黑
            int times = 0;
            while (marked[B] != USHRT_MAX) {//直到遇到起点标志为止
                times++;
                B = marked[B];//链式倒推会起点 也可以顺便把每一步记录下来
            }
            return times;
        }
        for (int p = 0; p < 16; p++)
            if (!marked[B^opt[p]]) {//由于是广搜 因而先到者必然比后到者次数少 因而忽略后到者 异或操作表示翻转
                marked[B^opt[p]] = B;//记录来源状态
                q.push(B^opt[p]);
            }
    }
    return -1;//所有状态都已搜索过 无法完成
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    for (int p = 15; p >= 0; p--) {
        char c;
        scanf("%c", &c);//input
        if (p % 4 == 0)
            getchar();//吞掉换行
        if (c == 'b')
            B |= 1 << p;//以或和左移操作置位 棋盘左上角为高位
    }
    marked[B] = USHRT_MAX;//代表全黑的情况 但由于不会有哪个状态由终点衍生 因而作为起点标志
    int ans = bfs(B);
    if (ans == -1)
        printf("Impossible\n");//output
    else
        printf("%d\n", ans);//output
}

EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值