方格填数
如下的10个格子
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
答案为:1580
典型的全排列+判断的问题。
解法一、
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int a[] = { 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; //若此排列中有一个元素与其相邻位置的元素连续即返回false
return true; //即此排列满足题意要求
}
void fun(int k){ //递归回溯生成全排列的函数,数组中不能有重复元素
if(k==10) { //递归边界,即已生成一种排列
if(check()){
ans++; //若满足条件 ans++;
}
return;
}
//k后面的数字都可以放在k位
for(int i=k;i<=9;i++){
int t = a[i];a[i]=a[k];a[k]=t;
fun(k+1); //递归
t = a[i];a[i]=a[k];a[k]=t; //回溯
}
}
int main() {
fun(0);
cout << ans;
return 0;
}
使用C++的next_permutation函数实现全排列:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int a[] = { 0,1,2,3,4,5,6,7,8,9 };//初始化数组
bool check() {
//check()函数体与上个代码段相同
}
int main() {
int ans = 0;
do {
if (check()) { //对生成的排列进行检查
ans++; //若符合题意要求ans++;
}
} while (next_permutation(a, a + 10)); //使用next_permutation函数生成a数组元素的全排列
cout << ans;
return 0;
}
若对next_permutation函数不熟悉可以查看相关的介绍:
https://so.csdn.net/so/search/all?q=next_permutation&t=all&p=1&s=0&tm=0&lv=-1&ft=0&l=&u=
解法二、
将把三行四列的格子声明为一个五行六列的二维数组、便于在判断10个格子的每个元素与相邻格子是否满足条件时,不需要考虑其边界情况。
#include <iostream>
#include <cmath>
using namespace std;
int a[5][6];
bool table[10]={0}; //判断数字0-9是否被使用
int ans = 0;
void Init(){
for(int i=0;i<5;i++){
for(int j=0;j<6;j++){
//将数组元素全部初始化为-10,以至于在判断0-9的格子周围格子时不受题意条件的影响
a[i][j] = -10;
}
}
}
bool check(int x,int y) {
//两层循环,判断a[x][y]与相邻的八个格子是否有连续的数字
for(int i=x-1;i<=x+1;i++){
for(int j=y-1;j<=y+1;j++){
if(abs(a[i][j]-a[x][y]) == 1) return false; //若有一个连续的即返回false
}
}
return true; //满足题意条件,返回true
}
void fun(int x,int y){
if(x==3 && y==4){ //递归边界,已经生成一种满足题意的排列
ans++;
return;
}
for(int i = 0;i<=9;i++){
if(table[i]==0){ //若i未使用,则进行操作
a[x][y] = i;
//填入一个数字即判断周围的格子是否有连续的,声明五行六列的二维数组的原因就在这里
if(!check(x,y)){
a[x][y]=-10;
continue; //若i不满足题意条件,则跳过本次循环,判断i+1在此格子是否满足;
}
table[i]= 1;//满足check的条件,即i已被使用
if(y==4) fun(x+1,1); //递归,列边界处理
else fun(x,y+1);
{table[i] = 0;a[x][y] = -10;} //执行完一次递归即回溯
}
}
}
int main() {
Init();
fun(1,2); //从二维数组的1行2列开始处理
cout << ans << endl ;
return 0;
}