zoukankan      html  css  js  c++  java
  • POJ2044 深搜+剪枝(云彩下雨)

    题意:
           有一个城镇,是4*4的大小的,然后你控制一块云彩,2*2的,你每天可以有9种走的方法,上下左右,或者不动,走的时候可以走1或者2步,云彩所在的地方肯定会下雨,然后给你做多365天的安排,要求某些日子的某些城镇不能下雨(因为有**节日),还有任何地方都不能有连续超过6天不下雨。


    思路:
           首先9种走法,做多连续六点不下雨,这个可以直接DFS深搜,(BFS不知道行不行,没试过,主要担心的是内存,反正目测BFS队列QUEUE占用的内存太大),如果不优化的话的话时间复杂度可是9^365根本受不了啊,然后就是考虑优化,也就是mark走过的状态,关键是怎么标记这个状态,一开始我是想找16个素数,然后根据每个格子的步数去计算每个16个步数得到的一个特别值去hash状态,可以失败了,找素数的方法不行,举个例子 3 * 7 + 7 * 3 = 7 * 3 + 3 * 7,然后就是考虑状态压缩,可是按照最笨的放发的话状态压缩的9^16中状态,后来我自己优化了下,还是9^12种状态,还是不行,后来看了别人的解释,一开始有疑惑,想了好久才说服自己,说下标程,可以只考虑四个点,假如当前用云彩的左上角表示云彩,那么我们只要考虑的四个点就是 1 1 ,1 3 ,3 1,3 3也就是云彩在四个角落的时候的坐标,判断下雨天数的时候可以只判断这四个,还有mark的时候也是mark[t][n][a][b][c][d] t 天数,a云彩当前位置(只记录左上角,离散化之后就9个),a b c d分别是当前那4个关键位置连续没下雨的天数,然后就直接DFS就行了,下面解释下为什么这样是对的:
    (1)充分性 : 只要这四个点都满足天数不大于7 那么全图肯定都满足,这个自己看下就知道了,因为把图分成四块,这四个关键点肯定是每一个块中连续不下雨天数最长的。
    (2)必要性 : 如果全图都满足连续不下雨情况,那么这四个关键点必然满足,因为要想让(1 ,1) ,(1 ,4) ,(4 ,1) ,(4 ,4)都满足,那么必须走这4个关键点,别的点照顾不到这。
    (3)还有就是只用这四个点代表唯一性是否正确,这个我犹豫了好久,就是这个地方一开始怎么也想不明白,现在说下我目前的理解。
    假如当前状态
    1111 2222        1111 2222   如果按照上面的那个方法mark必须证明这两个状态是一
    1111 2222        1111 2222   个状态,我的理解是四个关键位置的连续不下雨天数一定
    3333 4444        3332 4443   比自己所在的模块的所有天数都大,无论什么时候,那么
    3333 4444        3332 4443   也就是说如果以后出现问题肯定是这四个最大的中的某个
                                 出现问题,也就是别的点永远都只是陪衬,所以 陪衬的点
                                 怎么样不会影响总的状态以及最终的趋势,所以这种mark                               的方法是正确的,这个是我自己的理解。





    #include<stdio.h>
    #include<string.h>


    int DAY[367];
    bool mark[366][10][8][8][8][8];
    int ys[12] = {0 ,1 ,2 ,3 ,0 ,4 ,5 ,6 ,0 ,7 ,8 ,9};
    int dir[9][2] = {0 ,0 ,0 ,1 ,0 ,-1 ,1 ,0 ,-1 ,0 ,0 ,2 ,0 ,-2 ,2 ,0 ,-2 ,0};
    int OK ,T;


    bool ok(int t ,int x ,int y ,int a[])
    {


        int aa = (x - 1) * 4 + y;
        int bb= (x - 1 + 1) * 4 + y;
        int cc = (x - 1) * 4 + y + 1;
        int dd = (x - 1 + 1) * 4 + y + 1;
        if(x < 1 || x > 3 || y < 1 || y > 3)
        return 0;
        if(a[1] >= 7 || a[2] >= 7 || a[3] >= 7 || a[4] >= 7)
        return 0;
        if(((1 << aa) & DAY[t]) || ((1 << bb) & DAY[t]) || ((1 << cc) & DAY[t]) || ((1 << dd) & DAY[t]))
        return 0;
        if(mark[t][ys[aa]][a[1]][a[2]][a[3]][a[4]]) return 0;
        return 1;


    }


    void DFS(int t ,int x ,int y ,int a[])
    {
        if(t == T) OK = 1;
        if(OK) return ;
        int b[5];
        for(int i = 0 ;i < 9 ;i ++)
        {
            if(t == 0 && i) break;
            int nowt = t + 1;
            int nowx = x + dir[i][0];
            int nowy = y + dir[i][1];
            for(int j = 1 ;j <= 4 ;j ++)
            b[j] = a[j] + 1;
            if(nowx == 1 && nowy == 1) b[1] = 0;
            if(nowx == 1 && nowy == 3) b[2] = 0;
            if(nowx == 3 && nowy == 1) b[3] = 0;
            if(nowx == 3 && nowy == 3) b[4] = 0;
            if(ok(nowt ,nowx ,nowy ,b))
            {
                mark[nowt][ys[(nowx-1)*4+nowy]][b[1]][b[2]][b[3]][b[4]] = 1;
                DFS(nowt ,nowx ,nowy ,b);
            }
        }
        return ;
    }


    int main ()
    {
        int i ,j;
        while(~scanf("%d" ,&T) && T)
        {
            memset(DAY ,0 ,sizeof(DAY));
            for(i = 1 ;i <= T ;i ++)
            {
                int tmp;
                for(j = 1 ;j <= 16 ;j ++)
                {
                    scanf("%d" ,&tmp);
                    DAY[i] = DAY[i] | (tmp << j);
                }
            }
            memset(mark ,0 ,sizeof(mark));
            OK = 0;
            int a[5];
            a[1] = a[2] = a[3] = a[4] = 0;
            DFS(0 ,2 ,2 ,a);
            printf("%d " ,OK);
        }
        return 0;
    }







  • 相关阅读:
    等价类划分测试用例设计方法
    测试用例设计中的测试数据设计方案
    测试用例的编写原则
    边界值分析法---测试用例设计方法
    判定表---测试用例设计方法
    错误猜测法---测试用例设计方法
    myeclipse(2015)中创建简单的Maven项目的步骤(用于生成可执行jar文件)------》myeclipse2015
    myeclipse如何设置字体?
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds -----》myeclipse2015
    mysql数据库视图连接出现2003····错误
  • 原文地址:https://www.cnblogs.com/csnd/p/12062476.html
Copyright © 2011-2022 走看看