zoukankan      html  css  js  c++  java
  • POJ 1753 Flip Game (DFS + 枚举)

    题目:http://poj.org/problem?id=1753

    这个题在開始接触的训练计划的时候做过,当时用的是DFS遍历,其机制就是把每一个棋子翻一遍。然后顺利的过了。所以也就没有深究。

    省赛前一次做PC2遇到了差点儿一模一样的题,仅仅只是是把棋盘的界限由4X4改为了5X5,然后一直跑不出结果来,可是当时崔老湿那个队过了,在最后总结的时候。崔老湿就说和这个题一样,只是要枚举第一行进行优化。

    我以为就是恢复第一行然后第二行以此类推,只是手推一下结果是6不是4,就知道这个有问题。

    问了崔老湿,问了+才。我发现我的思路不对。应该是用DFS把第一行全部可能出现的情况枚举出来,然后再一行一行的推导。

    第一次A的代码:

    //DFS
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int MAP[5][5];
    int ans = 999999;
    
    int pd (void)
    {
        int i,k;
        int ans = 0;
        for (i = 0;i < 4;i++)
            for (k = 0;k < 4;k++)
                ans += MAP[i][k];
    
        if (ans == 0 || ans == 16)
            return 1;
    
        return 0;
    }
    
    int fan (int x,int y)
    {
        MAP[x][y] = !MAP[x][y];
    
        if (x - 1 >= 0)
            MAP[x - 1][y] = !MAP[x - 1][y];
        if (y - 1 >= 0)
            MAP[x][y - 1] = !MAP[x][y - 1];
        if (x + 1 < 4)
            MAP[x + 1][y] = !MAP[x + 1][y];
        if (y + 1 < 4)
            MAP[x][y + 1] = !MAP[x][y + 1];
        return 0;
    }
    
    int dfs (int x,int y,int t)
    {
        if (pd ())
        {
            if (ans > t)
                ans = t;
    
            return 0;
        }
    
        if (x >= 4 || y >= 4)
            return 0;
    
        int nx = (x + 1) % 4,ny = y + (x + 1) / 4;
    
        dfs (nx,ny,t);
        fan (x,y);
    
        dfs (nx,ny,t + 1);
        fan (x,y);
    
        return 0;
    }
    
    int main()
    {
        int i,k;
    
        for (i = 0;i < 4;i++)
        {
            char s[5];
            scanf ("%s",s);
    
            for (k = 0;k < 4;k++)
                if (s[k] == 'b')
                    MAP[i][k] = 1;
                else
                    MAP[i][k] = 0;
        }
    
        dfs (0,0,0);
    
        if (ans == 999999)
            puts ("Impossible");
        else
            printf ("%d
    ",ans);
        return 0;
    }
    


    用枚举的代码:

    //DFS + 枚举
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int MAP[5][5];
    int tMAP[5][5];
    int ans = 999999;
    
    int pd (int n)
    {
        int i;
        int re = 0;
        for (i = 0;i < 4;i++)
            re += tMAP[3][i];
    
        if (n == 1 && re == 0)   //防止前三行为1最后一行0以及反之等的特殊情况
            return 1;
    
        if (n == 2 && re == 4)
            return 1;
    
        return 0;
    }
    
    int fan (int x,int y)
    {
        tMAP[x][y] = !tMAP[x][y];
    
        if (x - 1 >= 0)
            tMAP[x - 1][y] = !tMAP[x - 1][y];
        if (y - 1 >= 0)
            tMAP[x][y - 1] = !tMAP[x][y - 1];
        if (x + 1 < 4)
            tMAP[x + 1][y] = !tMAP[x + 1][y];
        if (y + 1 < 4)
            tMAP[x][y + 1] = !tMAP[x][y + 1];
        return 0;
    }
    
    int fanM (int x,int y)
    {
        MAP[x][y] = !MAP[x][y];
    
        if (x - 1 >= 0)
            MAP[x - 1][y] = !MAP[x - 1][y];
        if (y - 1 >= 0)
            MAP[x][y - 1] = !MAP[x][y - 1];
        if (x + 1 < 4)
            MAP[x + 1][y] = !MAP[x + 1][y];
        if (y + 1 < 4)
            MAP[x][y + 1] = !MAP[x][y + 1];
        return 0;
    }
    
    int dfs (int x,int y,int t)
    {
        if (x >= 1)
        {
            //枚举
            memcpy (tMAP,MAP,sizeof (MAP));
            int tmp = t;
            int i,k;
    
            for (i = 1;i < 4;i++)
            {
                for (k = 0;k < 4;k++)
                {
                    if (tMAP[i - 1][k] == 1)
                    {
                        fan (i,k);
                        tmp++;
                    }
                }
            }
    
            if (pd (1))
                ans = ans < tmp ? ans : tmp;
    
            memcpy (tMAP,MAP,sizeof (MAP));
            tmp = t;
    
            for (i = 1;i < 4;i++)
            {
                for (k = 0;k < 4;k++)
                {
                    if (tMAP[i - 1][k] == 0)
                    {
                        fan (i,k);
                        tmp++;
                    }
                }
            }
    
            if (pd (2))
                ans = ans < tmp ? ans : tmp;
            return 0;
        }
        int ny = (y + 1) % 4,nx = x + (y + 1) / 4;
    
        dfs (nx,ny,t);
        fanM (x,y);
    
        dfs (nx,ny,t + 1);
        fanM (x,y);
    
        return 0;
    }
    
    int main()
    {
        int i,k;
    
        for (i = 0;i < 4;i++)
        {
            char s[5];
            scanf ("%s",s);
    
            for (k = 0;k < 4;k++)
                if (s[k] == 'b')
                    MAP[i][k] = 1;
                else
                    MAP[i][k] = 0;
        }
    
        dfs (0,0,0);
    
        if (ans == 999999)
            puts ("Impossible");
        else
            printf ("%d
    ",ans);
        return 0;
    }
    


     

    其效果还是非常明显的

    把全部棋子枚举,转化为仅仅枚举第一行的棋子。就是这个题优化的思路。

  • 相关阅读:
    周强 201771010141 《面向对象程序设计(Java)》第十一周学习总结
    周强 201771010141《面对对象程序设计(java)》第十周学习总结
    周强 201771010141 《面向对象程序设计(java)》第九周实验总结
    周强201771010141《面向对象程序设计(java)》第六周学习总结
    周强201771010141《面向对象程序设计Java》第八周学习总结
    周强 201771010141 《面向对象程序设计(java)》第七周学习总结
    周强 201771010141《面向对象程序设计(java)》第四周学习总结
    «面向对象程序设计(java)»第三周学习总结 周强 201771010141
    周强 201771010141 《面向对象程序设计(java)》 第二周学习总结
    201771010109 焦旭超《面向对象程序设计(java)》第十二周学习总结
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5217254.html
Copyright © 2011-2022 走看看