题目链接:P1283 平板涂色
题面
题目描述
CE 数码公司开发了一种名为自动涂色机(APM)的产品。它能用预定的颜色给一块由不同尺寸且互不覆盖的矩形构成的平板涂色。
为了涂色,APM 需要使用一组刷子。每个刷子涂一种不同的颜色 Ci 。APM 拿起一把有颜色 Ci 的刷子,并给所有颜色为 Ci 且符合下面限制的矩形涂色:
为了避免颜料渗漏使颜色混合,一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色。例如图中矩形 F 必须在 C 和 D 涂色后才能涂色。注意,每一个矩形必须立刻涂满,不能只涂一部分。
写一个程序求一个使 APM 拿起刷子次数最少的涂色方案。注意,如果一把刷子被拿起超过一次,则每一次都必须记入总数中。
输入格式
第一行为矩形的个数 N。下面有 N 行描述了 N 个矩形。每个矩形有 5 个整数描述,左上角的 y 坐标和 x 坐标,右下角的 y 坐标和 x 坐标,以及预定颜色。
平板的左上角坐标总是 (0,0)。
输出格式
一个整数,表示拿起刷子的最少次数。
输入输出样例
输入 #1
7
0 0 2 2 1
0 2 1 6 2
2 0 4 2 1
1 2 4 4 2
1 4 3 6 1
4 0 6 4 1
3 4 6 6 2
输出 #1
3
说明/提示
(1le C_i le 20),(0 le x_i,y_i le 99),(1le N le 16)。
思路
这题数据范围很小,可以直接搜索。
搜索每一个矩形有没有被涂过,如果没有涂过,
先判断这个矩形能不能涂,用check函数来判断,代码内的注释已经给得非常详细了。
如果能涂的话,再看是不是和刷子颜色一样,如果不是,就++。
代码
#include <iostream>
using namespace std;
int n, ans, x1[20], _y1[20], x2[20], y2[20], color[20];
//y1是关键字,必须在前面加一个下划线
bool visit[20];
void search(int, int, int);
bool check(int);
int main()
{
cin >> n;
ans = n; //先把ans设为一个(在本题中)最大的值
for (int i = 1; i <= n; i++) {
cin >> _y1[i] >> x1[i] >> y2[i] >> x2[i] >> color[i]; //先输入y坐标,再输入x坐标
}
search(0, 0, -1);
cout << ans << endl;
return 0;
}
void search(int tot, int finish, int col)
{
if (tot >= ans)
return; // 如果总数已经大于ans的值了,就可以不用继续了
if (finish == n)
ans = tot; //如果已经搜索完毕了,就直接把tot的值赋给ans
for (int i = 1; i <= n; i++)
if (!visit[i] && check(i)) {
visit[i] = true;
if (color[i] == col) { //如果找到了是这个矩形那就给它涂色
search(tot, finish + 1, color[i]);
}
else { //如果找到的矩形颜色不一样,就finish++,继续涂色
search(tot + 1, finish + 1, color[i]);
}
visit[i] = false; //回溯
}
}
bool check(int k)
{
for (int i = 1; i <= n; i++)
if (!visit[i] //如果循环到的矩形没涂过色
&& _y1[i] == y2[k] //判断要涂色的矩形是否下好在循环到的矩形下方
//可通过判断循环到的矩形的下面那条边的纵坐标是否与
//要涂色的矩形上面那条边的纵坐标相等
&& ((x1[i] >= x1[k] && x1[i] <= x2[k]) //循环到的矩形的左边界在要涂色的矩形左右边界之间
|| (x2[i] >= x1[k] && x2[i] <= x2[k]))) //循环到的矩形的右边界在要涂色的矩形左右边界之间
return false;
return true;
}