P1283 平板涂色

题目传送门

数据范围很小,直接考虑状压或者暴搜,这里考虑状压。

那就需要考虑我们选了一个集合 SS,很自然能够想到把每个矩形是/否涂过色标记为 0/10/1,从而衍生为一个集合。

转移的话也很简单,在枚举所有集合 ii 的时候,直接枚举可以使用的颜色,大力模拟出来使用了当前画笔后的集合情况为 ss,方程就是:

dps=min(dps,dpi+1)dp_s=\min(dp_s,dp_i+1)

思路看起来很清晰,但是实际操作起来难度比较大,写到吐。

开始的时候应该先排序,按照左上角的横坐标来排,这样才能保证在从上往下覆盖的时候不会漏掉矩形。

在判断矩形的时候,考虑直接用一个数组标记矩形靠上的那条长上的所有点的覆盖情况,注意,当前矩形靠上的长和另一个矩形靠下的长在同一直线,但是交集为 11 的时候,题目不认为这属于“覆盖”的范畴,那么这个点就不能被标记了。

当然你也不能用一个二维数组去搞,因为很多点都是重合的,这样会漏掉信息。

同时可以发现,按照我们这样的设法,这题的状态数其实不会很多,跑起来飞快。

#include<bits/stdc++.h>
using namespace std;
const int N =100;
int dp[(1<<16)+20],vis2[N],p[N],c[N],vis[N],vis1[N],cnt,n;
struct node{
	int l1,r1,l2,r2;
}a[N];
bool cmp(node a,node b){
	return a.l1<b.l1;
}
void col(int x){
	for(int i=0;i<n;i++)
		if(x>>i&1==1)	vis1[i]=true;
}
bool check(int i){
	for(int j=0;j<n;j++){
		if(i==j||(a[i].l1!=a[j].l2)||vis1[j]==false)	continue;
		if(a[i].r1<a[j].r2&&a[j].r1<=a[i].r1)	for(int k=a[i].r1;k<=a[j].r2;k++)	vis2[k]=1;
		if(a[i].r2>a[j].r1&&a[j].r2>=a[i].r2)	for(int k=a[j].r1;k<=a[i].r2;k++)	vis2[k]=1;
	}
	for(int k=a[i].r1;k<=a[i].r2;k++)	if(vis2[k]==0)	return false;
	return true;
}
void Add(int now,int x){
	int lst=now;
	for(int i=0;i<n;i++){
		if(c[i]!=x||(lst>>i&1==1))	continue;
		bool f=true;
		memset(vis2,0,sizeof(vis2));
		if(a[i].l1!=0)	f=check(i);
		if(f==true)	vis1[i]=true,now|=(1<<i);	
	}
	dp[now]=min(dp[now],dp[lst]+1);	
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i].l1>>a[i].r1>>a[i].l2>>a[i].r2>>c[i];
		if(vis[c[i]]==false)	p[cnt++]=c[i],vis[c[i]]=true;
	}
	sort(a,a+n,cmp);
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	for(int i=0;i<(1<<n);i++){
		if(dp[i]==1061109567)	continue;
		for(int j=0;j<cnt;j++)
			memset(vis1,0,sizeof(vis1)),col(i),Add(i,p[j]);
	} 
	cout<<dp[(1<<n)-1]<<endl;
	return 0;
}
posted @   June_Failure  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示