LOJ 一本通系列 平板涂色
题目描述
原题来自:POJ 1691
CE 数码公司开发了一种名为自动涂色机(APM)的产品。它能用预定的颜色给一块由不同尺寸且互不覆盖的矩形构成的平板涂色。
为了涂色,APM 需要使用一组刷子。每个刷子蘸了颜色 CCC 。APM 拿起一把蘸有颜色 CCC 的刷子,并给所有颜色为 CCC 的矩形涂色。请注意,涂色有顺序要求:为了避免颜料渗漏使颜色混合,一个矩形只能在所有紧靠它上方的矩形涂色后,才能涂色。例如图中矩形 FFF 必须在 CCC 和 DDD 涂色后才能涂色。注意,每一个矩形必须立刻涂满,不能只涂一部分。
写一个程序求一个使 APM 拿起刷子次数最少的涂色方案。注意,如果一把刷子被拿起超过一次,则每一次都必须记入总数中。
输入格式
第一行为矩形的个数 NNN 。
下面有 NNN 行描述了 NNN 个矩形。每个矩形有 555 个整数描述,左上角的 yyy 坐标和 xxx 坐标,右下角的 yyy 坐标和 xxx 坐标,以及预定颜色。
输出格式
一行一个整数,表示拿起刷子的最少次数。
样例输入
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
数据范围与提示
对于全部数据,1≤N≤141 leq N leq 141≤N≤14,颜色号为 111 到 202020 的整数。保证平板的左上角坐标总是 (0,0)(0, 0)(0,0),坐标的范围是 000 到 999 。
题解:
一个矩形可以被涂,只有当它以上的矩形全已被染色。由此性质可以得出拓扑序。
先预处理出每个矩形的前驱(即先决条件),然后就可以dfs了。
注意剪枝:当前答案大于等于最优答案,退出。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,ans=15; 4 struct node{ 5 int x1,y1,x2,y2,w,s[18],t; 6 bool vis; 7 }a[15]; 8 inline int read() 9 { 10 int x=0,f=1; char ch=getchar(); 11 while (!isdigit(ch)) f=(ch=='-')?-f:f,ch=getchar(); 12 while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 13 return x*f; 14 } 15 bool check(int r) 16 { 17 for (int i=1; i<=a[r].t; ++i) 18 if (!a[a[r].s[i]].vis) return 0; 19 return 1; 20 } 21 void dfs(int x,int s,int last) 22 { 23 if (ans<=x) return; 24 if (s==n) { ans=std::min(ans,x); return; } 25 for (int i=1;i<=n;++i) 26 if(!a[i].vis && (check(i) || !a[i].x1)) 27 a[i].vis=1,dfs(x+(last!=a[i].w),s+1,a[i].w),a[i].vis=0; 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 for (int i=1; i<=n; i++) 33 scanf("%d%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2,&a[i].w); 34 for (int i=1; i<=n; i++) 35 for (int j=1; j<=n; j++) 36 if (i!=j && a[i].x1==a[j].x2 && !(a[j].y2<a[i].y1 || a[j].y1>a[i].y2)) 37 a[i].s[++a[i].t]=j; 38 dfs(0,0,0); printf("%d ",ans); 39 return 0; 40 }
加油加油加油!!!fighting fighting fighting!!!