POJ1020 - Anniversary Cake 解题报告

POJ1020 - Anniversary Cake 解题报告

原题解析

题目的意思是,分一块大正方形蛋糕,切成若干(n: [1, 16])块正方形小蛋糕(size: [1, 10])。问能够完整分完,还是分不完或者浪费。

题目要点

  1. 大蛋糕的尺寸没有说明,但是通过小蛋糕的最大数量和最大尺寸可以推断不超过40;
  2. 解题的思路容易想到枚举所有切法,所以用dfs深度优先搜索比较合适,搜索蛋糕的切法;
  3. 因为计算的是完整切完的方法,因此切割过程中必不会产生空隙,因此可以将40*40的问题优化,仅计算其每列的占用情况,既降维

示例代码

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

const int kCakeMaxSize = 40;

struct Status
{
    int cakeSize;
    int subCakeNum;
    int subCakeNumTable[kCakeMaxSize + 1];
    int cakeHightTable[kCakeMaxSize + 1];
    bool withoutWaste;
};

void input(Status& status);
void calc(Status& status);
void output(Status& status);

bool dfs(int usedCakeNum, Status& status);
int findLowestIndex(int& lowestSize, Status& status);
bool checkPickedCake(int pickedCakeSize, int lowestIndex, Status& status);
void pickCake(int pickedCakeSize, int lowestIndex, Status& status);
void backCake(int pickedCakeSize, int lowestIndex, Status& status);

int main()
{
    int caseNum;
    while (scanf("%d", &caseNum) != EOF)
    {
        for (int c = 0; c < caseNum; ++c)
        {
            Status status;
            input(status);
            calc(status);
            output(status);
        }
    }
    return 0;
}

void input(Status& status)
{
    memset(&status, 0, sizeof(status));

    scanf("%d %d", &status.cakeSize, &status.subCakeNum);
    for (int k = 0; k < status.subCakeNum; ++k)
    {
        int subCakeSize;
        scanf("%d", &subCakeSize);
        status.subCakeNumTable[subCakeSize]++;
    }
}

void calc(Status& status)
{
    int space = 0;
    for (int i = 1; i <= status.cakeSize; ++i)
    {
        space += status.subCakeNumTable[i] * i * i;
    }
    if (space == status.cakeSize * status.cakeSize)
    {
        status.withoutWaste = dfs(0, status);
    }
    else
    {
        status.withoutWaste = false;
    }
}

bool dfs(int usedCakeNum, Status& status)
{
    int subCakeMaxSize = 0;
    int lowestIndex = findLowestIndex(subCakeMaxSize, status);
    for (int cakeSize = subCakeMaxSize; cakeSize > 0; --cakeSize)
    {
        if (checkPickedCake(cakeSize, lowestIndex, status))
        {
            if (usedCakeNum + 1 == status.subCakeNum)
            {
                return true;
            }

            pickCake(cakeSize, lowestIndex, status);
            if (dfs(usedCakeNum + 1, status))
            {
                return true;
            }
            backCake(cakeSize, lowestIndex, status);
        }
    }
    return false;
}

int findLowestIndex(int& lowestSize, Status& status)
{
    int lstHight = kCakeMaxSize + 1;
    int lstIndex = kCakeMaxSize + 1;
    int lstSize = 0;
    bool seriesFlag = false;
    for (int i = 1; i <= status.cakeSize; ++i)
    {
        if (status.cakeHightTable[i] < lstHight)
        {
            lstHight = status.cakeHightTable[i];
            lstIndex = i;
            lstSize = 1;
            seriesFlag = true;
        }
        else if (status.cakeHightTable[i] == lstHight)
        {
            if (seriesFlag)
            {
                ++lstSize;
            }
        }
        else
        {
            seriesFlag = false;
        }
    }
    lowestSize = lstSize;
    return lstIndex;
}

bool checkPickedCake(int pickedCakeSize, int lowestIndex, Status& status)
{
    if (status.subCakeNumTable[pickedCakeSize] <= 0) return false;
    if (status.cakeHightTable[lowestIndex] + pickedCakeSize > status.cakeSize) return false;
    return true;
}

void pickCake(int pickedCakeSize, int lowestIndex, Status& status)
{
    --(status.subCakeNumTable[pickedCakeSize]);
    for (int i = 0; i < pickedCakeSize; ++i)
    {
        status.cakeHightTable[lowestIndex + i] += pickedCakeSize;
    }
}

void backCake(int pickedCakeSize, int lowestIndex, Status& status)
{
    ++(status.subCakeNumTable[pickedCakeSize]);
    for (int i = 0; i < pickedCakeSize; ++i)
    {
        status.cakeHightTable[lowestIndex + i] -= pickedCakeSize;
    }
}

void output(Status& status)
{
    if (status.withoutWaste)
    {
        printf("KHOOOOB!\n");
    }
    else
    {
        printf("HUTUTU!\n");
    }
}

数据参考

数据来自poj讨论区。

10 
21 16 5 7 2 4 8 9 4 2 3 2 4 2 9 6 4 4 
28 16 10 10 7 3 5 9 10 3 8 5 7 7 5 7 1 7 
13 11 1 2 2 8 1 2 3 7 1 4 4 
23 16 1 7 5 8 5 10 9 2 1 4 2 6 3 1 8 7 
26 16 3 7 10 9 8 3 1 9 6 6 8 2 10 1 5 4 
21 16 6 5 10 4 2 3 4 7 7 2 3 3 1 1 7 8 
18 14 2 6 3 1 2 3 9 9 4 5 7 2 1 2 
15 12 3 1 3 1 8 1 5 1 6 2 6 3 
22 15 2 6 8 5 4 7 9 9 4 5 4 3 6 3 4 
22 14 4 1 6 7 9 1 7 3 10 8 1 6 5 4 

HUTUTU! 
HUTUTU! 
HUTUTU! 
KHOOOOB! 
KHOOOOB! 
KHOOOOB! 
KHOOOOB! 
HUTUTU! 
HUTUTU! 
KHOOOOB! 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值