原题解析
题目的意思是,分一块大正方形蛋糕,切成若干(n: [1, 16])块正方形小蛋糕(size: [1, 10])。问能够完整分完,还是分不完或者浪费。
题目要点
- 大蛋糕的尺寸没有说明,但是通过小蛋糕的最大数量和最大尺寸可以推断不超过40;
- 解题的思路容易想到枚举所有切法,所以用dfs深度优先搜索比较合适,搜索蛋糕的切法;
- 因为计算的是完整切完的方法,因此切割过程中必不会产生空隙,因此可以将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!