poj 1020 分蛋糕问题

/*
 *  poj 1020 切蛋糕

    题目大意:
        求能否将一堆小正方形无重叠的拼接成一个大正方形?

    解题思路:
        回溯 + 剪枝

        按照从左到右,从上到下的顺序,枚举所有可以放置正方形的单元,尝试放入合适的小正方形。
        直到无法放入小正方形或者完全放完为止。

        1、因为小正方形的边长介于1~10之间,所以可以采用计数的方式来存储小正方形的个数。
        2、采用每列占用数的方式来存储大正方形的占用情况,同时用来查找下一个可能的安置单元。
        3、每次选择占用最少的列作为安置点 -- 该点必然是某个正方形的左上点,因为它的左上没有其他空置点了!
        4、从大到小选择小正方形,如果最终所有小正方形可以拼成大正方形的话,所有的小正方形都会用到的,
           同等的情况下选择大的,等于把更灵活、容易安排的小的放在了后面,有点贪心的感觉。但是如果
           选择大的不成功,不等于整个拼接就失败了,应该选择更小的正方形进行尝试。也就是传说中的回溯。
        
    剪枝:
        1、在安置点(最少占用列)尝试放置剩余的最大正方形时,出现超出边界的情况,可以直接返回false
           因为剩余空间最大的列居然都无法满足某个剩余正方形,则该正方形必然无法放下,因此无需进行
           进一步的搜素

        2、在安置点尝试放置某边长为a的小正方形失败,则所有后续为a的小正方形也无需尝试,直接进行
           更小边长正方形的尝试!

    最后:
        贪心的反例:
            10 8 4 4 3 3 3 3 3 3 3 1 1 1 1 1 -> 边长为10的大正方形,与2个4x4、7个3x3、5个1x1的小正方形

        如果贪心,会有如下解:
        
            4x4 4x4 空  空
            3x3 3x3 3x3 空
            3x3 3x3 3x3 空

            最终剩余一个3x3的小正方形无处安放。

        其实该例有解:
                3x3   3x3
            4x4 111   3x3
            3x3 3x3 1 
            3x3 3x3 1 4x4
*/

#include 
#include 

namespace {
    using namespace std;

    const int S_MAX = 40;
    int c[11], d[S_MAX]; // c存储边长为i的小正方形的个数,d存储每例的占用情况

    int n, S;
    bool splitable(int deepth)
    {
        // 所有正方形均被成功安置,返回成功
        if (deepth == n) return true;

        // 寻找安置点,从左到右,从上到下
        int x=S, y;
        for (int j=0; j0; --i)
        {
            if(c[i]==0) continue;

            if(x+i > S) return false; // 剪枝1

            if(y+i > S) continue; // 该处不能剪,y到头表示应该换更小的正方形来尝试,因为最终每个单元都要被用掉

            // 查看是否足够单元
            bool bEnough = true;
            for (int k=1; k d[y])
                {
                    bEnough = false;
                    break;
                }
            }

            if (!bEnough) continue;

            // 深搜
            c[i]--;
            for (int k=0; k> t;

    int sum, si;
    for (int k=0; k> S >> n;

        sum = 0; // 记得每次清0,否则只有第一次准
        memset(c, 0, sizeof(c));
        for (int i=1; i<=n; i++)
        {
            cin >> si;
            c[si]++;
            sum += si * si;
        }

        memset(d, 0, sizeof(d));
        if (sum==S*S && splitable(0))
        {
            cout << "KHOOOOB!" << endl;
        }
        else
        {
            cout << "HUTUTU!" << endl;
        }
    }
    
    return 0;
}



你可能感兴趣的:(搜索)