CF142C Help Caretaker 题解
题意:
本题要求我们在 \(n\times m\) 的方格中放置大小为 \(3\times3\) 的 T,可以旋转,但不能重叠。T 形如:
### #     #  #
 #  ### ###  #
 #  #     # ###
输出一种可以放置最多 T 的方案,使用不同的大写字母表示不同的 T。
思路:
我们可以使用搜索的方式枚举所有放置 T 的方案,若当前答案 \(nowans\) 大于最终答案 \(ans\) 则更新最优解。
但是一般的搜索会超时,我们需要对搜索进行剪枝。使用 \(c_{ij}\) 表示搜索至第 \(i\) 行第 \(j\) 列个方格时最大放置的 T 数量,可以发现若 \(nowans+1<c_{ij}\) 则表明当前方案不会比最后一次更新 \(c_{ij}\) 时的方案更好。
同时我们发现若 \(n=m=1\) 则搜索将会越界,所以需要特判。事实上,若 \(n<3\) 或 \(m<3\) 则均不能放置 T,可以同时特判。
代码:
#include<iostream>
#include<cstring>
#define i x
#define j y
#define judge if(cnt+1>=c[x][y])\
{c[x][y]=max(c[x][y],cnt);\
if(y==m-1)dfs(x+1,2,cnt+1);\
else dfs(x,y+1,cnt+1);}
using namespace std;
int n,m,ans,a[15][15],c[15][15];
//a[][] 为01状态数组,其中 a[i][j]=true 当且仅当第 i 行第 j 列的方格被 T 覆盖。
//c[][] 用来剪枝,具体用法见上文。
char b[15][15],d[15][15];
//b[][],d[][] 用来输出方案。
void dfs(int x,int y,int cnt)
{
	if(x==n)
	{
		if(ans<cnt)
		{
			ans=cnt;
			memcpy(d,b,sizeof(b));
		}
		return;
	}
	//更新方案。
	if(!a[i][j]&&!a[i-1][j]&&!a[i+1][j]&&!a[i-1][j-1]&&!a[i-1][j+1])
	{
		a[i][j]=a[i-1][j]=a[i+1][j]=a[i-1][j-1]=a[i-1][j+1]=1;
		b[i][j]=b[i-1][j]=b[i+1][j]=b[i-1][j-1]=b[i-1][j+1]='A'+cnt;
		judge
		a[i][j]=a[i-1][j]=a[i+1][j]=a[i-1][j-1]=a[i-1][j+1]=0;
		b[i][j]=b[i-1][j]=b[i+1][j]=b[i-1][j-1]=b[i-1][j+1]=0;
		//还原未放置 T 的状态。
	}
	if(!a[i][j]&&!a[i][j-1]&&!a[i][j+1]&&!a[i-1][j+1]&&!a[i+1][j+1])
	{
		a[i][j]=a[i][j-1]=a[i][j+1]=a[i-1][j+1]=a[i+1][j+1]=1;
		b[i][j]=b[i][j-1]=b[i][j+1]=b[i-1][j+1]=b[i+1][j+1]='A'+cnt;
		judge
		a[i][j]=a[i][j-1]=a[i][j+1]=a[i-1][j+1]=a[i+1][j+1]=0;
		b[i][j]=b[i][j-1]=b[i][j+1]=b[i-1][j+1]=b[i+1][j+1]=0;
	}
	if(!a[i][j]&&!a[i-1][j]&&!a[i+1][j]&&!a[i+1][j-1]&&!a[i+1][j+1])
	{
		a[i][j]=a[i-1][j]=a[i+1][j]=a[i+1][j-1]=a[i+1][j+1]=1;
		b[i][j]=b[i-1][j]=b[i+1][j]=b[i+1][j-1]=b[i+1][j+1]='A'+cnt;
		judge
		a[i][j]=a[i-1][j]=a[i+1][j]=a[i+1][j-1]=a[i+1][j+1]=0;
		b[i][j]=b[i-1][j]=b[i+1][j]=b[i+1][j-1]=b[i+1][j+1]=0;
	}
	if(!a[i][j]&&!a[i][j-1]&&!a[i][j+1]&&!a[i-1][j-1]&&!a[i+1][j-1])
	{
		a[i][j]=a[i][j-1]=a[i][j+1]=a[i-1][j-1]=a[i+1][j-1]=1;
		b[i][j]=b[i][j-1]=b[i][j+1]=b[i-1][j-1]=b[i+1][j-1]='A'+cnt;
		judge
		a[i][j]=a[i][j-1]=a[i][j+1]=a[i-1][j-1]=a[i+1][j-1]=0;
		b[i][j]=b[i][j-1]=b[i][j+1]=b[i-1][j-1]=b[i+1][j-1]=0;
	}
	//当可以放置中心点为(x,y)的 T 时,枚举四种情况。
	if(y==m-1)dfs(x+1,2,cnt);
	else dfs(x,y+1,cnt);
	//不放置 T,继续搜索。
	return;
}
int main()
{
	scanf("%d%d",&n,&m);
	if(n<3||m<3)
	{
		puts("0");
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)putchar('.');
			puts("");
		}
		exit(0);
	}
	//特判不能放置 T 的方格大小。
	dfs(2,2,0);
	//若中心点在边缘则显然不能放置 T,没有枚举的必要,所以可以直接从(2,2)开始,到达第 n 行则结束本次搜索。
	printf("%d\n",ans);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)putchar(d[i][j]==0?'.':d[i][j]);
		puts("");
	}
	return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号