题解 P1585 【魔法阵】
YellowBean_Elsa · · 题解
我觉得这题应该蓝。。。
首先看数据范围可知,这题就是个普通搜索。
然后按照题意,很快写出了一个简单的暴搜。
当然,加上了最显而易见的剪枝:如果当前答案已大于搜索已经得到的最小值,直接 return;
然而这样T飞了。。。
然后我们注意到,题目还有一个限制条件:每个格子必须且仅能经过一次
那么,如果在某一个状态时,我们可以判断此时已经不可能按要求走完魔法阵,则可以直接 return;
knock the blackboard!!!
经过画图,我们找到了一种这样的状态:
当我们走到一个位置时,如果已经走过它的上下,却没有走过它左右的任意一格,或者相反,已经走过它的左右,却没有走过它上下的任意一格,那么一定无法走完魔法阵,直接 return;
证明:如图,从A走到B的路径隔绝了C和D,因此不可能在不经过A到B路径的情况下同时走到C和D,证毕。
加上这个可行性剪枝后,就AC了。
//coder: Feliks-GMYB
#include<bits/stdc++.h>
using namespace std;
int n,m,k1,k2,ans=(1<<30);
bool vis[55][55];
int col[30][2];
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x;
}void dfs(int x,int y,int p,int mx){
//可行性剪枝
if(vis[x-1][y]&&vis[x+1][y]&&!vis[x][y+1]&&!vis[x][y-1])return;
if(!vis[x-1][y]&&!vis[x+1][y]&&vis[x][y+1]&&vis[x][y-1])return;
if(mx>ans)return;//显而易见的最优性剪枝
//按照公式要求进行操作
if(p<=((n*m)>>1)){
col[p][0]=x;
col[p][1]=y;
}else mx=max(mx,abs(col[p-n*m/2][0]-x)*k1+abs(col[p-n*m/2][1]-y)*k2);
if(p==n*m){//done the maze
if(mx<ans)ans=mx;
return;
}//尝试向四面走
if(!vis[x-1][y]){
vis[x-1][y]=1;
dfs(x-1,y,p+1,mx);
vis[x-1][y]=0;
}//up
if(!vis[x+1][y]){
vis[x+1][y]=1;
dfs(x+1,y,p+1,mx);
vis[x+1][y]=0;
}//down
if(!vis[x][y-1]){
vis[x][y-1]=1;
dfs(x,y-1,p+1,mx);
vis[x][y-1]=0;
}//left
if(!vis[x][y+1]){
vis[x][y+1]=1;
dfs(x,y+1,p+1,mx);
vis[x][y+1]=0;
}//right
}int main(){
n=read(),m=read(),k1=read(),k2=read();
//常见搜索防越界操作:
//地图四周初始时赋为已走过,防止搜索时走出地图
for(int i=0;i<=n+1;i++)
vis[i][0]=vis[i][m+1]=1;
for(int i=0;i<=m+1;i++)
vis[0][i]=vis[n+1][i]=1;
vis[1][1]=1;dfs(1,1,1,0);
printf("%d\n",ans);
return 0;
}
多嘴一句,这种可行性剪枝对于所有要求一笔画方格图的搜索都适用,也可看作一种实用技巧