问题描述
【题目描述】
【输出】
题目解析
这道题是一道经典的全排列+check()类型的题目,给出两种解题思路:
- 抓取9个数字分别填入不同的格子中最后出口处check()判断;
- 将方格补充成5×6的矩形,将方格空余位置用-10填充,如下图所示,因此在check()中只需要判断该位置九宫格内的情况即可,较方案一check()方法不仅代码量少,而且也可以完成提前剪枝的操作。
C++代码
全排列+check()
#include<bits/stdc++.h>
using namespace std;
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int ans = 0;
bool check() //相邻不连续对角也不能相邻
{
if(abs(a[0]-a[1])==1||
abs(a[0]-a[3])==1||
abs(a[0]-a[4])==1||
abs(a[0]-a[5])==1||
abs(a[1]-a[2])==1||
abs(a[1]-a[4])==1||
abs(a[1]-a[5])==1||
abs(a[1]-a[6])==1||
abs(a[2]-a[5])==1||
abs(a[2]-a[6])==1||
abs(a[3]-a[4])==1||
abs(a[3]-a[7])==1||
abs(a[3]-a[8])==1||
abs(a[4]-a[5])==1||
abs(a[4]-a[7])==1||
abs(a[4]-a[8])==1||
abs(a[4]-a[9])==1||
abs(a[5]-a[6])==1||
abs(a[5]-a[8])==1||
abs(a[5]-a[9])==1||
abs(a[6]-a[9])==1||
abs(a[7]-a[8])==1||
abs(a[8]-a[9])==1)
return false;
return true;
}
void f(int k) //考虑第k个位置
{
if(k==10)
{
bool b = check();
if(b) ans++;
return;
}
for(int i=k;i<10;i++) //生成全排列
{
//尝试位置i与位置k交换以此确定k位的值
{
int t = a[i];
a[i] = a[k];
a[k] = t;
}
f(k+1);
//回溯
{
int t = a[i];
a[i] = a[k];
a[k] = t;
}
}
}
int main()
{
f(0);
cout<<ans<<endl;
return 0;
}
全排列+提前剪枝
#include<bits/stdc++.h>
using namespace std;
int a[5][6];
int vis[10];
int ans = 0;
bool check(int i,int j)
{
for(int x=i-1;x<=i+1;x++) //周边九宫格走完
for(int y=j-1;y<=j+1;y++)
if(abs(a[x][y]-a[i][j])==1) return false;
return true;
}
void f(int x,int y)
{
if(x==3&&y==4)
{
ans++;
return;
}
for(int i=0;i<10;i++)
{
if(vis[i]==0)
{
a[x][y] = i;
if(!check(x,y)) //如果检查不成功,不合法
{
a[x][y] = -10; //恢复初始状态
continue; //接着执行下一次
}
vis[i]=1;
if(y==4) f(x+1,1); //如果一行走完了继续下一行
else f(x,y+1); //没走完y接着走
{
vis[i] = 0; //回溯
a[x][y] = -10;
}
}
}
}
void init()
{
for(int i=0;i<5;i++)
for(int j=0;j<6;j++)
a[i][j] = -10;
}
int main()
{
init();
f(1,2);
cout<<ans<<endl;
return 0;
}