大致题意:
墙上有一面黑板,现划分为多个矩形,每个矩形都要涂上一种预设颜色C。
由于涂色时,颜料会向下流,为了避免处于下方的矩形的颜色与上方流下来的颜料发生混合,要求在对矩形i着色时,处于矩形i上方直接相邻位置的全部矩形都必须已填涂颜色。
在填涂颜色a时,若预设颜色为a的矩形均已着色,或暂时不符合着色要求,则更换新刷子,填涂颜色b。
注意:
1、 当对矩形i涂色后,发现矩形i下方的矩形j的预设颜色与矩形i一致,且矩形j上方的全部矩形均已涂色,那么j符合填涂条件,可以用 填涂i的刷子对j填涂,而不必更换新刷子。
2、 若颜色a在之前填涂过,后来填涂了颜色b,现在要重新填涂颜色a,还是要启用新刷子,不能使用之前用于填涂颜色a的刷子。
3、 若颜色a在刚才填涂过,现在要继续填涂颜色a,则无需更换新刷子。
4、 矩形着色不能只着色一部分,当确认对矩形i着色后,矩形i的整个区域将被着色。
首先要注意输入数据,每个矩形信息的输入顺序是 y x y x c,而不是 x y x y c
若弄反了x y坐标怎样也不会AC的.....
这题主要思路就是把长方形看成点,然后判断上下的长方形是否连通,即上面的长方形的ry=下方的长方形的ly,并且不能错开,得有相连部分,用数组记录他们的连通情况,并且记录每个点的入度。DFS回溯解决。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct rect
{
int lx,ly,rx,ry,col;
}r[16];
int n,ans,deg[16];//每个长方形的入度,当他上面与几块长方形连接时,就有多少入度,如果上面一块被涂色了,就入度-1,入度为0是就是待涂色
int m[16][16];//表明两个长方形之间的连通情况
int vis[16];//长方形是否着色
void build()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(r[i].ry==r[j].ly&&!(r[i].lx>=r[j].rx||r[i].rx<=r[j].lx))
{
m[i][j]=1;
deg[j]++;
}
}
}
}
void dfs(int dep,int cnt,int color)
{
if(cnt>=ans) return;//当前情况大于等于最优解,剪枝pass
if(dep==n)
{
ans=cnt;//前面已经pass掉了cnt大于等于ans的情况
return;
}
for(int i=0;i<n;i++)
{
if(!deg[i]&&!vis[i])
{
vis[i]=1;
for(int j=0;j<n;j++)
{
if(m[i][j]) deg[j]--;
}
if(r[i].col==color) dfs(dep+1,cnt,color);
else dfs(dep+1,cnt+1,r[i].col);//判断完颜色后决定是否换刷子
for(int j=0;j<n;j++)//回溯到上一个结点。进入下一种情况
{
if(m[i][j]) deg[j]++;
}
vis[i]=0;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d %d %d %d %d",&r[i].ly,&r[i].lx,&r[i].ry,&r[i].rx,&r[i].col);
}
ans=20;
memset(m,0,sizeof(m));
memset(deg,0,sizeof(deg));
memset(vis,0,sizeof(vis));
build();
dfs(0,0,0);//第一次拿起刷子也算一次pick-up,所以都从0开始;
printf("%d\n",ans);
}
return 0;
}