题目大意不多说了,主要说点题目中应该注意的问题。
1.如何放:基本就是大家所说的dfs,注意减枝即可;
2.怎么放才是正确的 : 每次选择放得最少的列,在其基础上放置对应的正方形(注意减枝)。
该题数据很弱,即你按照行搜索,优先放置列上剩余最少的(如左图),也可以AC,正确做法是横向放置,不然在dfs时容易出现右图的问题。ps:由小到大也会存在这个问题的,只不过显示的图片不一样。
正确做法是选取剩余最多的列放置正方形,而不是单纯按列排满,如下图所示,就绝对不会出现中间留有空白的情况。
正常搜索会出现超时的情况
bool dfs(int x)
{
total_times++;
int result = 0, left = 0;
for (int i = 9; i >= 0; i--)
{
if (input[i])
{
left = 1;//有剩余数据则表示好需要搜索
if (set(x, i + 1)) // 设置对应的列数据,失败时能还原现场
{
int next_x = maxLeft();//获取下个最大的列
input[i] --;
result = dfs(next_x);
if (result)
{
return true;
}
else
{
input[i] ++;
clearLast(x, i + 1);//还原现场
}
}
}
}
if (left == 0)
{
return true;
}
return result;
}
这里最大的问题就是未对set(x, i + 1)进行减枝,导致dfs失败时不停调用,出现tle。其实在确定下一个dfs的列序号时,就能获取到其最大能放入的宽度。具体看代码(79MS),应该还有优化空间。如果有疑问,或者代码中存在问题,欢迎一起交流
#include<iostream>
#include<string>
#include <iomanip>
#include<math.h>
#include <fstream>
using namespace std;
int input[10] = {};
int data[10] = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 };
int a[40] = {};
int size;
int total_times = 0;
//置位
bool set(int x, int length)
{
if (x + length > size)
{
return false;
}
int index = x, error = 1;
for (; index < length + x; index++)
{
a[index] += length;
if (a[index]> size)
{
error = 0;
break;
}
}
if (!error)
{
//还原现场
for (int i = x; i <= index; i++)
{
a[i] -= length;
}
}
return error;
}
//选占用最短的x,顺便获取支持最长长度
void maxLeft(int &x, int &maxLength)
{
x = 0;
for (int i = 1; i < size; i++)
{
if (a[x] > a[i])
x = i;
}
maxLength = 0;
for (int i = x; i < size; i++)
{
if (a[x] == a[i])
{
maxLength ++;
}
else
{
break;
}
}
}
//清楚上次操作
void clearLast(int x, int length)
{
for (int i = x; i < x + length; i++)
{
a[i] -= length;
}
}
//x为选择的列,maxLength为选择该列时最大支持的正方形大小
bool dfs(int x, int maxLength)
{
total_times++;
int result = 0, left = 0;
for (int i = 9; i >= 0; i--)
{
if (input[i])
{
//正方形放完即认为结束,否则继续dfs
left = 1;
if (maxLength >= i && set(x, i + 1)) //maxLength这里用于减枝,不然会tle
{
int next_x, next_maxLength;
maxLeft(next_x, next_maxLength);
input[i] --;
result = dfs(next_x, next_maxLength);
if (result)
{
return true;
}
else
{
//还原现场
input[i] ++;
clearLast(x, i + 1);
}
}
}
}
if (left == 0)
{
return true;
}
return result;
}
int main()
{
//ifstream in("d:\\document\\test.txt");
int max_case = 0, temp_value, cur_case = 0;
cin >> max_case;
getchar();
while (cur_case < max_case)
{
total_times = 0;
cur_case++;
int count = 0;
int max_size = 0, max_value = 0, temp = 0;
memset(input, 0, 10 * sizeof(int));
memset(a, 0, 40 * sizeof(int));
cin >> size >> count;
for (int i = 0; i < count; i++)
{
cin >> temp;
max_size += data[temp - 1];
input[temp - 1] ++;
}
if (max_size != size * size)
{
cout << "HUTUTU!" << endl;
}
else
{
if (dfs(0, 10))
{
cout << "KHOOOOB!" << endl;
}
else
{
cout << "HUTUTU!" << endl;
}
}
}
system("pause");
return 0;
}