解题思路
直接枚举每个点的五种状态(向左、向右、向上、向下、不动)显然会超时,于是我们可以考虑枚举聚点,即蜘蛛汇聚的点。
我们可以贪心地考虑,若点 x x x 被选为聚点,则令其周围四个格子的蜘蛛都走到 x x x 处一定是最优的。这是因为我们要使聚点的数量尽可能少,既然一个点已经被选为聚点就需要最大化它的价值。于是,dfs 的大致思路就出来了:找到一个当前还有蜘蛛的格子,它本身及它周围四个点都有可能是聚点,进行枚举。找到聚点后将其周围的点状态标记为没有蜘蛛,最后加上最优性剪枝即可。
代码示例
#include<bits/stdc++.h>
using namespace std;
int n,m,a[110][110];
int ans=0x3f3f3f3f;
int dx[10]={0,1,-1,0,0,0};
int dy[10]={0,0,0,1,-1,0};
void dfs(int step){
int xx,yy,flag=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==1){
xx=i,yy=j,flag=1;
break;
}
}
if(flag) break;
}
if(flag==0){
ans=min(ans,step);
return;
}
if(step+1>=ans) return;
for(int i=1;i<=5;i++){
int tx=xx+dx[i],ty=yy+dy[i];
if(tx<=0||ty<=0||tx>=n+1||ty>=m+1) continue;
vector<pair<int,int> > O;
for(int j=1;j<=5;j++){
if(a[tx+dx[j]][ty+dy[j]]==1){
a[tx+dx[j]][ty+dy[j]]=0;
O.push_back(make_pair(tx+dx[j],ty+dy[j]));
}
}
dfs(step+1);
for(int i=0;i<O.size();i++) a[O[i].first][O[i].second]=1;
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=1;
ans=n*m;
dfs(0);
cout<<n*m-ans<<endl;
return 0;
}