题目:https://www.luogu.com.cn/problem/P1283
题目简述:用蘸有各种颜色的刷子涂被划分出各个区块的地板,保证每个区块涂色之前,在它上面的区块早已经涂色完毕,求抬起刷子的最小值
思路:n<=16,来一个剪枝就足够了
时间复杂度:O(能过)
#include<bits/stdc++.h>
using namespace std;
int n,i,ans,a1[17],b1[17],a2[17],b2[17],c[17],v[17]={0};
//ans是拿刷子的数量
//b是纵,a是横,1是左上,2是右下
//c表示该区块需要的颜色,v表示该区块是否被涂色
inline bool f(int k){//检查
for(int i=1;i<=n;++i){//一个区块一个区块的来
if(b2[i]==b1[k]&&((a1[i]>=a1[k]&&a1[i]<=a2[k])||(a2[i]>=a1[k]&&a2[i]<=a2[k]))&&!v[i]){
//首先,如果循环中的区块的右下角的点的纵坐标
//与当前正在检查的区块的左上角的点的坐标相等
//则可以知道,他们的上下边界是没有空隙的
//如果还满足前正在检查的区块的左边界
//在循环中的区块的左右边界之间
//或者还满足正在检查的区块的右边界
//在循环中的区块的左右边界之间
//那么就证明,循环中的区块
//就是紧靠正在检查的区块上方的区块
//这种时候告诉的,上面的这个区块没有涂色
//那“正在检查的区块”也就无法涂色了
return 0;//再见
}
}
//上面每个区块都没让它再见
//那这个区块就是可以涂的了
return 1;//返回“真,即“它可以涂色”
}
inline void dfs(int t,int s,int o){
if(t>=ans){//当前次数已经大于当前已知的最小值
return;//再见
}
if(s==n){//搜完了,也没有再见
ans=t;//更新最小值
return;//手动再见
}
for(int i=1;i<=n;i++){//一个个区块的来
if(!v[i]&&f(i)){//没上过色并且可以上色
v[i]=1;//标记“已涂色”
if(c[i]==o){//如果还是原来的那种颜色
dfs(t,s+1,o);//不用换刷子
}
else{//如果不是
dfs(t+1,s+1,c[i]);//换刷子
}
v[i]=0;//回溯
}
}
}
int main(){
scanf("%d",&n);//常规输入
ans=n;//就算是每个区块换一次刷子
//换n次也就够了,所以ans的初始值定为n就足矣应对
for(i=1;i<=n;++i){//常规输入
scanf("%d%d%d%d",&b1[i],&a1[i],&b2[i],&a2[i]);
scanf("%d",&c[i]);
}
dfs(0,0,0);//从0搜起
printf("%d",ans);
return 0;
}
题目总结:重难点
在于对这个格子是否能涂色的检查
剪枝并没有考到太多
这提醒了我们,多注意数据范围,免得WA或者是做无用功
浙公网安备 33010602011771号