【题目描述】
CE数码公司开发了一种名为自动涂色机(APM)的产品。它能用预定的颜色给一块由不同尺寸且互不覆盖的矩形构成的平板涂色。
为了涂色,APM需要使用一组刷子。每个刷子涂一种不同的颜色C。APM拿起一把有颜色C的刷子,并给所有颜色为C且符合下面限制的矩形涂色:
为了避免颜料渗漏使颜色混合,一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色。例如图中矩形F必须在C和D涂色后才能涂色。注意,每一个矩形必须立刻涂满,不能只涂一部分。
写一个程序求一个使APM拿起刷子次数最少的涂色方案。注意,如果一把刷子被拿起超过一次,则每一次都必须记入总数中。
【输入】
第一行为矩形的个数N。下面有N行描述了N个矩形。每个矩形有5个整数描述,左上角的y坐标和x坐标,右下角的y坐标和x坐标,以及预定颜色。
颜色号为1到20的整数。
平板的左上角坐标总是(0, 0)。
坐标的范围是0..99。N小于16。
【输出】
拿起刷子的最少次数。
【输入样例】
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
【输出样例】
3
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
const int N = 1000000 + 5;
using namespace std;
struct Rectangle {
int x1, y1, x2, y2;
int color;
}rect[20];//结构体
bool vis[20], G[40][40];
int res = 15;//刷的次数的最大上限
bool judge(int x)//这一块能不能涂色
{
if (rect[x].x1 == 0)//这一块处于第一层,肯定可以涂色,返回真
return true;
for (int i = rect[x].y1 + 1; i <= rect[x].y2; i++)//对这一块进行遍历
if (G[rect[x].x1][i] == 0)//这一快已经被遍历过来,但是暂时没法继续搜索,所以,返回假
return false;//返回假
return true;//返回真
}
void update(int x, int sta)
{
for (int i = rect[x].x1 + 1; i <= rect[x].x2; i++)
for (int j = rect[x].y1 + 1; j <= rect[x].y2; j++)//遍历此块
G[i][j] = sta;//把其中每一块都变成step
}
void dfs(int p, int k, int num, int n) {//第p块板子刷第k次,累积了num块板子,总共有n块板子
if (k > res)//可行性剪枝,刷的次数比上限还要大,不再继续搜,直接返回上限
return;//返回
if (num == n)//已经刷了N块板子了,res等于上限和搜索结果的最小值
res = min(res, k);
for (int i = 1; i <= n; i++) //从第一块到第N快进行遍历
{
if (vis[i]==false && judge(i)==true) //这一块没有遍历过,并且可以涂色
{
update(i, 1);//将图中所有的数据都赋值成1
vis[i] = true;//此图已经遍历
num++;//刷过的板子数+1
if (rect[i].color == rect[p].color)//如果第i块板子与第p块板子要涂的颜色相同
dfs(i, k, num, n);//对第i块板子进行深搜,应为颜色相同,不需要再拿刷子,所以K不变
else //如果颜色不同
{
dfs(i, k+1, num, n);//对第i看块板子进行搜索(注意k值要+1)毕竟多刷了一次
}
//如果这两次搜索都不成功,
update(i, 0);//将图中每一个数值都变成0
vis[i] = false;//没有进行遍历
num--;//涂刷次数-1
}
}
}
int main() {
int n;
scanf("%d", &n);//输入矩阵个数
for (int i = 1; i <= n; i++)
scanf("%d%d%d%d%d", &rect[i].x1, &rect[i].y1, &rect[i].x2, &rect[i].y2, &rect[i].color);//输入左上坐标,右下坐标,以及预定颜色
dfs(0, 0, 0, n);//进行深搜
printf("%d\n", res);//输出结果
return 0;
}