题意分析
一个 n × m n \times m n×m 的棋盘,每个格子一开始有一只蜘蛛,每次蜘蛛可以向四联通方向走一格,或者停留在原地不动,最多有多少格子没有蜘蛛?
思考
众所周知,题目的数据范围限制了我们的解法,于是我们看到数据范围:
1
≤
n
×
m
≤
40
1≤n×m≤40
1≤n×m≤40 ,进而推出
max
(
n
,
m
)
≤
6
\max(n,m)≤6
max(n,m)≤6 ,有了这个推断后,我们有了第一个解法:直接暴力 DFS 。
但是,我们马上又会发现问题。每个点都有 5 种情况,这样显然会超时。这时,我们将思路放回到题目本身。既然要让空格最多,那么自然需要有蜘蛛的格子最少。即,我们需要尽可能多的蜘蛛聚集在尽可能少的格子上,我们把这样的格子叫做聚点,于是我们决定枚举聚点。
代码(此解绝非正解):
#include<iostream>
#include<cstdio>
using namespace std;
struct node{
int x,y;
};
int n,m;
int ans;
bool spider[100][100];
int dx[5]={1,-1,0,0,0};
int dy[5]={0,0,1,-1,0};
void dfs(int x){
int xx,yy;
bool flag=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(spider[i][j]){
xx=i;yy=j;flag=1;//找到一个聚点
}
}
if(flag)break;//如果已经找到过聚点
}
if(!flag){//统计答案
ans=min(ans,x);
return ;
}
if(x+1>=ans)return ;
for(int i=0;i<5;i++){//可以从五个方向到达一个聚点(当然有本来就在聚点的)
int nx=xx+dx[i];
int ny=yy+dy[i];
if(nx<1||nx>n||ny<1||ny>m)continue;
queue<node>q;
for(int k=0;k<5;k++){
if(spider[nx+dx[k]][ny+dy[k]]){
spider[nx+dx[k]][ny+dy[k]]=0;
node tmp;
tmp.x=nx+dx[k],tmp.y=ny+dy[k];
q.push(tmp);
}
}
dfs(x+1);
while(!q.empty()){
spider[q.front().x][q.front().y]=1;
q.pop();
}
}
}
int main(){
cin>>n>>m;
ans=n*m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
spider[i][j]=1;
}
}
dfs(0);
cout<<n*m-ans<<"\n";//ans是最少的聚点数量
return 0;
}
完结撒花!