一个正方形的镇区分为 N*N(1≤N≤7) 个小方块。农场位于方格的左上角,集市位于左下角。
Betsy 穿过小镇,从左上角走到左下角,刚好经过每个方格一次。
| | | |
| F********** |
| | | * |
------------*—
| | | * |
| ***** | * |
| * | * | * |
——----*—
| * | * | * |
| M | ****** |
请你帮忙计算 Betsy 有多少种不同的旅行方案。
Input
输入一行一个整数 N(1 \le N \le 7)
Output
输出一行表示不同的路径数。
Sample Input Copy
3
Sample Output Copy
2
这题一看就是DFS的经典问题要遍历所有的路线,尝试一波暴力搜索
#include
#include
using namespace std;
const int maxn=105;
int v[maxn][maxn];
int dr[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,ans=0;
void dfs(int x,int y,int step)
{ int tx,ty;
if(x==n&&y==1&&step==n*n)
{
ans++;
return ;
}
for(int i=0;i<4;i++)
{
tx=x+dr[i][0];
ty=y+dr[i][1];
if(tx>0&&tx<=n&ty>0&&ty<=n&&!v[tx][ty])
{
v[tx][ty]=1;
dfs(tx,ty,step+1);
v[tx][ty]=0;
}
}
}
int main()
{
cin>>n;
v[1][1]=1;
dfs(1,1,1);
printf("%d",ans);
return 0;
}
但数据范围过大,会在6的时候就被卡住
此时就要想到如何舍弃一些必不可能的解,把这些解快速的筛掉;
1.第一种能想到的剪枝手段就是不能提前就到达终点去
if(x == n && y == 1)//剪枝1,不能提前到达终点
{
if(sum==n*n) ans++;
return;
}
2.第二个剪枝手段是你所在目前地的上下方向和左右方向如果其中一组走过而另外一组未走过这时候可以直接剪枝筛掉,因为已经无法遍历了;
if((map[x][y-1] && map[x][y+1] && !map[x-1][y] && !map[x+1][y]) ||
(!map[x][y-1] && !map[x][y+1] && map[x-1][y] && map[x+1][y])) //剪枝2,孤立区域剪枝
return;
2.第三种剪枝手段就比较难想一些就是要对目前地的周围的必经地进行判断如果多于一个直接剪掉
只有一个的话就直接走那个必经之地,没有的话就对周围的地区都遍历一次
int get(int x, int y)
{
int t=0;
for(int k=0;k<4;k++)
if(!map[x+pos[k][0]][y+pos[k][1]])
t++;
return t;
}
//未经之地的个数
``` for(int i=0;i<4;i++)//剪枝3,格子的度的处理
{
int X=x+pos[i][0],Y=y+pos[i][1];
if(map[X][Y] || (X==n && Y==1)) continue;
if(get(X,Y)<2)
{
count++;
mx=X;
my=Y;
}
}
if(count>1)
return;
else
{
if(count==1)
{
map[mx][my]=1;
dfs(mx,my,sum+1);
map[mx][my]=0;
}
else
for(int i=0;i<4;i++)
{
int X=x+pos[i][0], Y=y+pos[i][1];
if(!map[X][Y])
{
map[X][Y]=1;
dfs(X,Y ,sum+1);
map[X][Y]=0;
}
}
}
}
完整代码便是这样的
#include
#include
using namespace std;
bool map[9][9];
int pos[][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int n,ans=0;
int get(int x, int y)
{
int t=0;
for(int k=0;k<4;k++)
if(!map[x+pos[k][0]][y+pos[k][1]])
t++;
return t;
}
void dfs(int x, int y, int sum)
{
if(x == n && y == 1)//剪枝1,不能提前到达终点
{
if(sum==n*n) ans++;
return;
}
if((map[x][y-1] && map[x][y+1] && !map[x-1][y] && !map[x+1][y]) ||
(!map[x][y-1] && !map[x][y+1] && map[x-1][y] && map[x+1][y])) //剪枝2,孤立区域剪枝
return;
int mx,my,count=0;
for(int i=0;i<4;i++)//剪枝3,格子的度的处理
{
int X=x+pos[i][0],Y=y+pos[i][1];
if(map[X][Y] || (X==n && Y==1)) continue;
if(get(X,Y)<2)
{
count++;
mx=X;
my=Y;
}
}
if(count>1)
return;
else
{
if(count==1)
{
map[mx][my]=1;
dfs(mx,my,sum+1);
map[mx][my]=0;
}
else
for(int i=0;i<4;i++)
{
int X=x+pos[i][0], Y=y+pos[i][1];
if(!map[X][Y])
{
map[X][Y]=1;
dfs(X,Y ,sum+1);
map[X][Y]=0;
}
}
}
}
int main(){
cin >> n;
for(int i=1;i<=n;i++) //处理边界
map[1][1]=map[0][i]=map[n+1][i]=map[i][0]=map[i][n + 1]=1;
dfs(1,1,1);
cout<<ans<< endl;
return 0;
}