问题 C: 平板涂色
时间限制: 1 Sec 内存限制: 512 MB
题目描述
CE 数码公司开发了一种名为自动涂色机(APM)的产品。它能用预定的颜色给一块由不同尺寸且互不覆盖的矩形构成的平板涂色。
为了涂色,APM 需要使用一组刷子。每个刷子涂一种不同的颜色。APM拿起一把蘸有颜色 C的刷子 。并给所有颜色为C且符合下面限制的矩形涂色。为了避免颜料渗漏导致颜色混合,一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色。例如图中矩形 F 必须在 C 和 D 涂色后才能涂色。注意,每一个矩形必须立刻涂满,不能只涂一部分。
写一个程序求一个使 APM 拿起刷子次数最少的涂色方案。注意,如果一把刷子被拿起超过一次,则每一次都必须记入总数中。
![](http://1xuan.top/upload/image/20190710/20190710161707_34944.jpg)
为了涂色,APM 需要使用一组刷子。每个刷子涂一种不同的颜色。APM拿起一把蘸有颜色 C的刷子 。并给所有颜色为C且符合下面限制的矩形涂色。为了避免颜料渗漏导致颜色混合,一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色。例如图中矩形 F 必须在 C 和 D 涂色后才能涂色。注意,每一个矩形必须立刻涂满,不能只涂一部分。
写一个程序求一个使 APM 拿起刷子次数最少的涂色方案。注意,如果一把刷子被拿起超过一次,则每一次都必须记入总数中。
输入
第一行为矩形的个数 N 。
下面有 N 行描述了 N 个矩形。每个矩形有 5 个整数描述,左上角的 y 坐标和 x 坐标,右下角的 y 坐标和 x 坐标,以及预定颜色。
颜色号为 1 到 20 的整数。平板的左上角坐标总是 (0,0),坐标的范围是0…99。N小于16。
下面有 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
思路:这道题一看上去就知道是搜索,但洛谷上好像有一堆dalao都是用dp过的。蒟蒻瑟瑟发抖。因为这题的数据实在太水,所以搜索是根本不用去考虑剪
枝,只用在当前次数大于等于ans时返回就可以了。不过这道题里唯一的难点就是如何判断矩形的上下关系,这个点卡了我两天。
处理好之后,只需在dfs函数里枚举颜色就好了。
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct lhy 4 { 5 int x1,y1,x2,y2,color;//设一个结构体来储存每一个矩形的信息 6 }a[20]; 7 int n,ans=999999,maxn_color,flag[20]; 8 bool f[20][20],color_check[25]; 9 bool check(int t)//判断该矩形是否可涂 10 { 11 for(int i=1;i<=n;i++) 12 { 13 if(f[t][i]==1&&flag[i]==0) return false; 14 } 15 return true; 16 } 17 void dfs(int color_now,int s,int sum)//当前的颜色 步数 已图的块数 18 { 19 if(s>=ans) return ;//唯一的剪枝 20 if(sum==n) 21 { 22 ans=s; 23 return ; 24 } 25 for(int i=1;i<=maxn_color;i++)//枚举颜色 26 { 27 if(i!=color_now&&color_check[i]==1) 28 { 29 int glq=0; 30 for(int j=1;j<=n;j++) 31 { 32 if(flag[j]==0&&a[j].color==i&&check(j)==true) 33 { 34 flag[j]=1; 35 glq++; 36 } 37 else if(flag[j]>=1&&a[j].color==i) flag[j]++; 38 } 39 if(glq>0) dfs(i,s+1,sum+glq); 40 for(int j=n;j>=1;j--)//不要忘记回溯 41 { 42 if(flag[j]==1&&a[j].color==i&&check(j)==true) 43 { 44 flag[j]=0; 45 glq--; 46 } 47 else if(flag[j]>1&&a[j].color==i) 48 { 49 flag[j]--; 50 } 51 } 52 } 53 } 54 } 55 int main() 56 { 57 scanf("%d",&n); 58 for(int i=1;i<=n;i++) 59 { 60 scanf("%d%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2,&a[i].color); 61 color_check[a[i].color]=1; 62 maxn_color=max(a[i].color,maxn_color); 63 } 64 for(int i=1;i<=n;i++) 65 { 66 for(int j=1;j<=n;j++) 67 { 68 if(i!=j&&f[j][i]==0) 69 { 70 if(a[i].x1==a[j].x2&&a[i].y1<=a[j].y2&&a[i].y2>=a[j].y1) f[i][j]=1;//最重要的一点!!!!判断矩形的上下关系 71 } 72 } 73 } 74 dfs(0,0,0); 75 printf("%d",ans); 76 return 0; 77 }
这题总的来说并不难,但想要在考场上拿到满分还是有一定难度的。希望这篇题解能对正在考模拟赛的你产生些许帮助。