江苏省省赛 方格覆盖 题解

给定一个 n × n n\times n n×n 的矩形,其中从左上角开始,对角线上连续的 k k k 个格子中有障碍物。你可以把若干 1 × 2 1\times2 1×2 的小矩形放置到该大矩形中,要求是放置的两个小矩形不能占据相同的格子,且不能碰到障碍物。例如右图是 n = 1 , k = 2 n=1,k=2 n=1,k=2 的例子,我们放置了 6 个 的小矩形。
在这里插入图片描述
给定 n , k n,k n,k,请你输出一个方案,使得放置的 1 × 2 1\times2 1×2 小矩形尽可能多。可以证明, n = 4 , k = 2 n=4,k=2 n=4,k=2 时,至多只能放置 6 6 6 个小矩形。

这题本质上就是一个贪心

方法1:横着扫,然后竖着扫

#include <bits/stdc++.h>
using namespace std;
int a[55][55],s;
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=k;i++)a[i][i]=-1;//障碍的放置,从左上角开始
    for(int i=1;i<=n;i++)//逐行扫,查看是否能放横着的
    	for(int j=1;j<n;j++)
    		if(a[i][j]==0&&a[i][j+1]==0){//查看是否有地方放,如果有放
    			a[i][j]=++s;
    			a[i][j+1]=s;//标号
			}
	for(int j=1;j<=n;j++)//逐列扫,查看是否能放竖着的
		for(int i=1;i<n;i++)
			if(a[i][j]==0&&a[i+1][j]==0){//查看是否有地方放,如果有放
				a[i][j]=++s;
				a[i+1][j]=s;//标号
			}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			if(a[i][j]==-1)cout<<0<<" ";
			else cout<<a[i][j]<<" ";//随便用什么格式输出,不妨用一个空格输出
		cout<<endl;
	}
	return 0;
}
/*
至于这种简单的贪心的正确性
考试时,我没有想到如何证明它是对的
我们可以稍微感性的去想一想
如果有剩余的格子
你就要让剩余的格子放在一起,你可以去尝试一下,总是不能把剩余的格子放在一起
*/

方法2:螺旋扫

考试结束后,王星钱说他是用了螺旋扫的方法,这种方法很巧妙,显然易见它是对的,只是码量稍微的大了一点点

先做一遍螺旋矩阵

#include <bits/stdc++.h>
using namespace std;
int a[55][55],s,f,x,y;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int fx[4]={1,-1,-1,1};
int main(){
    int n;
    cin>>n;
    int bonder[4]={1,n,n,1};
	x=1,y=1;
	for(int i=1;i<=n*n;i++){//n*n个格子
		a[x][y]=i;
		if(x+dx[f]<bonder[0]||y+dy[f]>bonder[1]||x+dx[f]>bonder[2]||y+dy[f]<bonder[3])bonder[f]+=fx[f],f=(f+1)%4;//进行螺旋
		x+=dx[f],y+=dy[f];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			cout<<a[i][j]<<" ";
		cout<<endl;
	}
	return 0;
}

确保对了之后开始进行赋值

#include <bits/stdc++.h>
using namespace std;
int a[55][55],s,f,x,y;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int fx[4]={1,-1,-1,1};
int main(){
    int n,k;
    cin>>n>>k;
    int bonder[4]={1,n,n,1};
    for(int i=1;i<=k;i++)a[i][i]=-1;//障碍的放置,从左上角开始
	x=1,y=1;//要这样写,否则会错k=0的点
	for(int i=1;i<=n*n;i++){//n*n个格子
		if(x+dx[f]<bonder[0]||y+dy[f]>bonder[1]||x+dx[f]>bonder[2]||y+dy[f]<bonder[3])bonder[f]+=fx[f],f=(f+1)%4;//进行螺旋
		if(a[x][y]==0&&a[x+dx[f]][y+dy[f]]==0){//赋值
			a[x][y]=++s;
			a[x+dx[f]][y+dy[f]]=s;
		}
		x+=dx[f],y+=dy[f];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			if(a[i][j]==-1)cout<<0<<" ";
			else cout<<a[i][j]<<" ";//随便用什么格式输出,不妨用一个空格输出
		cout<<endl;
	}
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值