Painting A Board
Description
The CE digital company has built an Automatic Painting Machine (APM) to paint a flat board fully covered by adjacent non-overlapping rectangles of different sizes each with a predefined color.
To color the board, the APM has access to a set of brushes. Each brush has a distinct color C. The APM picks one brush with color C and paints all possible rectangles having predefined color C with the following restrictions: To avoid leaking the paints and mixing colors, a rectangle can only be painted if all rectangles immediately above it have already been painted. For example rectangle labeled F in Figure 1 is painted only after rectangles C and D are painted. Note that each rectangle must be painted at once, i.e. partial painting of one rectangle is not allowed. You are to write a program for APM to paint a given board so that the number of brush pick-ups is minimum. Notice that if one brush is picked up more than once, all pick-ups are counted. Input
The first line of the input file contains an integer M which is the number of test cases to solve (1 <= M <= 10). For each test case, the first line contains an integer N, the number of rectangles, followed by N lines describing the rectangles. Each rectangle R is specified by 5 integers in one line: the y and x coordinates of the upper left corner of R, the y and x coordinates of the lower right corner of R, followed by the color-code of R.
Note that:
Output
One line for each test case showing the minimum number of brush pick-ups.
Sample Input 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 Sample Output 3 Source |
提示
题意:一面墙上要涂满颜色,且涂满颜色的部分都是矩阵,矩阵大小以左上角和右下角坐标的形式给出,最多有n(1<=n<=15)块,坐标范围是[0,99](坐标以[y,x]的形式给出),颜色编号从1到20。涂颜色的规则:为了防止刚刷上的颜料会往下流并它下面另一种颜色混合,所以涂颜色的时候上方必须已涂颜色或者与要涂的颜色相同。
对于刷子的使用:当前刷了颜料A后如果以后还刷颜料A可以不换刷子,否则要换。并且之前刷过颜料A,但现在刷过颜料B时,依然需要重新刷一把刷子。求出最少需要多少刷子才能完成任务。
思路:
坐标较小我们可以用二维数组来维护墙的状态,假设数组mark[100][100]全为0,矩阵左上角坐标sx,sy,右下角坐标tx,ty。先初始化mark[0][0~99]全为1,表示左上角坐标sy为0的矩阵可以涂了,因为它们是最上面的部分。之后利用dfs+回溯来搜索最优解:
判断(sx,sy)~(tx,sy)这条线上是否都做过标记,如果都有说明上面已被涂满颜色,当前矩阵满足条件,之后对(sx,ty)~(tx,ty)做上标记。
示例程序
Source Code
Problem: 1691 Code Length: 1609B
Memory: 424K Time: 0MS
Language: G++ Result: Accepted
#include <stdio.h>
#include <string.h>
struct
{
int sx,sy,tx,ty,kind;
}a[15];
int num,v[15],mark[100][100]; //num:所需刷子数,v[]:访问节点记录,mark[][]:维护墙的状态
int judge(int pos) //是否满足被涂的条件
{
int i;
for(i=a[pos].sx;a[pos].tx>=i;i++)
{
if(mark[a[pos].sy][i]==0)
{
return 0;
}
}
return 1;
}
void dfs(int pos,int deep,int ans,int n)
{
int i,i1;
if(ans==num) //没有比当前num更小的情况
{
return;
}
if(deep==n) //全都已涂完
{
num=ans;
return;
}
for(i=0;n>i;i++)
{
if(v[i]==0&&judge(i)==1)
{
v[i]=1;
for(i1=a[i].sx;a[i].tx>=i1;i1++)
{
mark[a[i].ty][i1]=1;
}
if(pos!=-1&&a[pos].kind==a[i].kind) //如果上一个的颜色和当前相同不需要换刷子
{
dfs(i,deep+1,ans,n);
}
else
{
dfs(i,deep+1,ans+1,n);
}
for(i1=a[i].sx;a[i].tx>=i1;i1++) //墙状态回溯
{
mark[a[i].ty][i1]=0;
}
v[i]=0; //节点回溯
}
}
}
int main()
{
int m,i,n,i1;
scanf("%d",&m);
for(i=1;m>=i;i++)
{
scanf("%d",&n);
for(i1=0;n>i1;i1++)
{
scanf("%d %d %d %d %d",&a[i1].sy,&a[i1].sx,&a[i1].ty,&a[i1].tx,&a[i1].kind);
}
num=n; //初始化最大所需刷子数为矩阵个数
memset(v,0,sizeof(v));
memset(mark,0,sizeof(mark));
for(i1=0;100>i1;i1++)
{
mark[0][i1]=1;
}
dfs(-1,0,0,n);
printf("%d\n",num);
}
return 0;
}