POJ 1753 基础搜索 DFS 七

本文解析了POJ1753翻转游戏问题,通过深入理解题目要求,采用深度优先搜索(DFS)算法求解最少翻转次数使4x4棋盘上所有棋子统一颜色。文章探讨了搜索空间的正确评估方式,并分享了实现过程中的关键技巧。
摘要由CSDN通过智能技术生成

细节决定成败,代码  尤其更甚!微笑

 

POJ 1753 Flip Game:http://poj.org/problem?id=1753

题目大意 : 4X4的棋盘上随机摆放了黑或白朝上的棋子。 对任意一颗棋子翻面,其上下左右的棋子也会一同执行翻面操作

  问,最少的反面次数,使得棋盘上所有棋子都为黑色或白色。

 

起初不能理解:一个棋盘上每个棋子只能翻一次,翻偶数次等于没有翻,这句话。

后来把思维掰回这个位置。。

 

  后来又有一种错误的思考: 棋盘是4X4,则第一次有16个地方可以翻,第二次有15个地方可以翻,....,所以一共有   16 的阶乘次翻法,搜索次数已经爆炸了....O__O "…

  看了看网上的讨论,恍然大悟.. 要搜索的次数是 翻棋的位置的  组合! 而不是排列。而16 的阶乘次,恰恰是16个点的排列,而不是选取组合的操作。

  也就是说,总共搜索的次数最多 为2^16次,也就是65536.

 

选择DFS,思路很清晰:

  从第一个点开始,翻或不翻,递归下一个点

 

  每一次棋盘的情况都次保存下来岂不是大得很?

  将16位展开用16位的字符串表示棋子颜色,(写博客时意识到不用也可以的,因为我用的是DFS,写的时候复杂化  了)

  因为是DFS,所以只要对满足题意的翻动次数与 记录的ans值取较小就好了

  错了一次,因为递归越界终止条件应该置于更新答案后面才对....

 

其实就是暴力搜索的DFS,用DFS什么位压缩都不用见鬼去吧。。。

DFS:

 

#include"cstdio"
#include"cstring"
#include"queue"
#include"iostream"
#include"algorithm"
using namespace std;
#define inf 109
#define loop(x,y,z) for(x=y;x<z;x++)

int ans=inf;
int pos[16];
int change[5]={0,4,-4,1,-1};
int book[4][4];

int pan(int n,int m)
{
    if(n+m<0||n+m>=16)return 0;
    int t=n%4;
    if(t==0&&m==-1)return 0;
    else if(t==3&&m==1)return 0;
    return 1;
}

void dfs(int t,int sum,int step)
{

    if(sum==0||sum==16)
    {
        ans=min(ans,step);
        return;
    }
    if(t==16)return;
    dfs(t+1,sum,step);
    int i;
    loop(i,0,5)
    {
        int j=change[i];
        if(pan(t,j))
            {
                if(pos[t+j]=='1'){pos[t+j]='0';sum--;}
                else {pos[t+j]='1';sum++;}
            }
    }
    dfs(t+1,sum,step+1);

    loop(i,0,5)
    {
        int j=change[i];
        if(pan(t,j))
            {
                if(pos[t+j]=='1')pos[t+j]='0';
                else pos[t+j]='1';
            }
    }

}

int main()
{
    int i,j;
    char a[5][5];
    int sum=0;
    loop(i,0,4)
        scanf("%s",&a[i]);
    loop(i,0,4)
        loop(j,0,4)
        {
            int t=i*4+j;
            if(a[i][j]=='w'){pos[t]='1';sum++;}
            else pos[t]='0';
        }
    dfs(0,sum,0);
    if(ans==inf)printf("Impossible\n");
    else printf("%d\n",ans);
    return 0;
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值