给定一个 的矩形,其中从左上角开始,对角线上连续的 个格子中有障碍物。你可以把若干 的小矩形放置到该大矩形中,要求是放置的两个小矩形不能占据相同的格子,且不能碰到障碍物。例如右图是 的例子,我们放置了 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;
}