GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版
题目有两种思考方式:
-
遍历队长,对每个队长生成可能的矩形,递归所有情况看看能不能得到结果。
-
直接遍历整个正方形的所有座位。对这个座位放到一个矩形中,如果这个矩形符合要求(内部包含一个队伍且没有重叠),则递归遍历。
方案1超时,方案2最后AC了。可能是因为方案1重复遍历的次数太多。
这里还是想提一下方案1的代码,一开始我将整个正方式所有座位表示出来,如果上面有队伍就设置对应位置为队伍序号。对于一个新的队伍,尝试所有可行的矩形排列。在每个矩形排列中,遍历所有座位看有没有重叠。
后面我优化了方案,不遍历所有座位了,而是将问题转化为这个矩形和已有的队伍矩形比较,看有没有重叠。方案是看两个矩形的中心距离有没有超过边长/2。(虽然最后还是超时)
最后方案2的AC代码如下:
cpp
#include <stdio.h>
#include <string.h>
int arr[35][35];
int n, k;
struct Group
{
int x, y;
int num;
bool hasFind;
};
// 下标从1开始
Group groups[30] = {};
int glen;
bool computed(int index);
// 判断单个矩形是否符合要求
bool judgeRect(int xmin, int ymin, int xmax, int ymax)
{
int i, j;
for (i = xmin; i <= xmax; ++i)
{
for (j = ymin; j <= ymax; ++j)
{
if (arr[i][j])
return false;
}
}
return true;
}
// 对矩形设置值
void setRect(int xmin, int ymin, int xmax, int ymax, int v)
{
int i, j;
for (i = xmin; i <= xmax; ++i)
for (j = ymin; j <= ymax; ++j)
arr[i][j] = v;
}
int judgeTeam(int xmin, int ymin, int xmax, int ymax)
{
int i, j;
int index = -1;
for (i = 1; i < glen; ++i)
{
if (groups[i].hasFind)
continue;
if (groups[i].x >= xmin && groups[i].x <= xmax && groups[i].y >= ymin && groups[i].y <= ymax)
{
if (index != -1)
return -1;
index = i;
}
}
if (index == -1)
return index;
if (groups[index].num != (xmax - xmin + 1) * (ymax - ymin + 1))
return -1;
return index;
}
bool computed(int x, int y)
{
if (x >= n)
return true;
if (y >= n)
return computed(x + 1, 0);
if (arr[x][y])
return computed(x, y + 1);
int i, j;
int t;
for (i = x; i < n; ++i)
{
for (j = y; j < n; ++j)
{
if (!judgeRect(x, y, i, j))
continue;
t = judgeTeam(x, y, i, j);
if (t <= 0)
continue;
groups[t].hasFind = true;
setRect(x, y, i, j, t);
if (computed(x, y + 1))
return true;
setRect(x, y, i, j, 0);
groups[t].hasFind = false;
}
}
return false;
}
void output()
{
int i, j;
int groupMap[30] = {};
int gi = 0;
for (i = 0; i < n; ++i)
{
for (j = 0; j < n; ++j)
{
if (!groupMap[arr[i][j]])
groupMap[arr[i][j]] = ++gi;
printf("%c", groupMap[arr[i][j]] + 'A' - 1);
}
putchar('\n');
}
}
int main()
{
int i, j, kt;
char c;
while (scanf("%d %d", &n, &k) == 2 && n > 0 & k > 0)
{
memset(groups, 0, sizeof(groups));
memset(arr, 0, sizeof(arr));
glen = 0;
kt = 1;
for (i = 0; i < n; ++i)
{
getchar();
for (j = 0; j < n; ++j)
{
c = getchar();
if (c != '.')
{
groups[kt] = {i, j, c - '0', false};
++kt;
}
}
}
glen = kt;
if (!computed(0, 0))
{
printf("xxx\n");
continue;
}
output();
}
return 0;
}