题目大意:
墙上有一块区域被分成了n个矩形,每个矩形要涂上各自的颜色。为了保证完美要求这一块区域可以进行涂色的条件是它上方的所有区域都已经涂好颜色,这样就不会有后续的操作影响这块区域的颜色。但是如果两块区域颜色不同就要换涂颜色用的刷子。问最少需要换几次。
解题思路:由于这题有一个限制条件,即上方的所有区域都已经涂好颜色,所以肯定是要求一个满足条件的拓扑序列,既然这样就很好办了,把上下两个相邻的矩形建立一条由上到下的有向边,然后dfs去搜索满足条件的拓扑序列。
AC:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f;
struct node
{
int xl,yl,xr,yr;
int c;
}rec[20];
struct Edge
{
int k,next;
}edge[50];
int n,cnt,pre[50],indegree[50],ans;
bool vis[20];
bool cmp(node a,node b)
{
return a.yl < b.yl;
}
void addedge(int u,int v)
{
edge[cnt].k = v;
edge[cnt].next = pre[u];
pre[u] = cnt++;
}
void dfs(int cur,int tmp,int dep)
{
if(dep == n) //所有点都找到
{
if(tmp < ans) ans = tmp;
return;
}
if(tmp >= ans) return; //当前的解大于已知最优解
for(int i = pre[cur]; i != -1; i = edge[i].next)
{
int k = edge[i].k;
indegree[k]--;
}
for(int i = 1; i <= n; i++)
{
if(vis[i] == true) continue;
if(indegree[i] == 0)
{
vis[i] = true;
if(rec[i].c != rec[cur].c)
dfs(i,tmp+1,dep+1);
else dfs(i,tmp,dep+1);
vis[i] = false;
}
}
for(int i = pre[cur]; i != -1; i = edge[i].next) //把修改的入度恢复原状
{
int k = edge[i].k;
indegree[k]++;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(pre,-1,sizeof(pre));
memset(vis,false,sizeof(vis));
memset(indegree,0,sizeof(indegree));
cnt = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d%d%d%d%d",&rec[i].yl,&rec[i].xl,&rec[i].yr,&rec[i].xr,&rec[i].c);
sort(rec+1,rec+1+n,cmp);
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
{
if(rec[i].yr != rec[j].yl) continue;
if(rec[i].xl >= rec[j].xl && rec[i].xr <= rec[j].xr)
{
addedge(i,j);
indegree[j]++;
}
else if(rec[i].xl <= rec[j].xl && rec[i].xr >= rec[j].xr)
{
addedge(i,j);
indegree[j]++;
}
else if(rec[i].xl < rec[j].xr && rec[i].xl > rec[j].xl)
{
addedge(i,j);
indegree[j]++;
}
else if(rec[i].xr < rec[j].xr && rec[i].xr > rec[j].xl)
{
addedge(i,j);
indegree[j]++;
}
}
ans = inf;
for(int i = 1; i <= n; i++)
if(indegree[i] == 0)
{
vis[i] = true;
dfs(i,1,1);
vis[i] = false;
}
printf("%d\n",ans);
}
return 0;
}