N queens N皇后问题
What is Dynamic Programming ?
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
定义
Dynamic Programming = recursive (递归) + Memorize (备忘录)
条件 最优子结构 (问题的最优解包含子问题的最有解) + 子问题重叠
实现方式 自底向上动态规划法 + 自顶向下动态规划法 (取决于 计算的顺序)
动态规划算法的例子
字符串算法 等 最长公共子序列 最长递增子序列 最长公共子串 编辑距离
图论有效求解法 寻找图中最短距离 所有顶点间最短路径等
矩阵连乘算法
0/1 背包问题
DESC N-Queens 问题描述:
Question:给出 n × n 的棋盘,返回 棋盘上放至 n 个 queens 的 解法
规则:queue 所在的行,列,以及对角线 不允许放置第二个queue
简化 四皇后问题:
在4×4格的国际象棋上摆放四个皇后,使其不能互相攻击,
即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
Analysis 分析
n \* n 按照行 递归 搜索 可行 情况 ,回溯处理解
边界条件 递归 至n行
每个一步处理3个条件:
S1 当前列 是否占用
S2 当时 行是否占用
S3 对角线位置是否被占用
不满足条件回溯到上一个步骤
(x-y+2 \* n) : 2n-1 条 / 对角线 值范围 \[0, 3n\]
(x+y) 2n-1 条 \\ 对角线 值范围 \[0, 2n-1\]
class Solution{
// 冲突条件 rows[] hills[] dales[] 使用0 1 表示是否占用
public boolean isNotUnderAttack( int row, int col , int n , int [] rows, int [] hills, int [] dales ) {
int res = rows[col] + hills[row -col + 2 * n ] + dales[row +col];
return ( res == 0) ? true :fase ;
}
public int backTrack( int row , int count , int n,, int [] rows, int [] hills, int [] dales ) {
for ( int col = 0; col < n ; col++{
if( isNotUnderAttack(row,col,n,rows,hills,dales){
// place_queen
rows[col] = 1;
hills[row -col + 2 * n ] = 1;
dales[row +col ] = 1 ;
// 边界条件 n queens already placed
if( row +1 == n ) count++ ;
else count = backTrack( row +1 , count , n, rows , hills, dales);
// remove queen
rows[col] = 0;
hills[row -col + 2 * n ] = 0;
dales[row + col] = 0;
}
}
return count;
}
public int totalNQueens (int n){
// 初始化 数组
int rows[] = new int[n];
int hills[] = new int [3 * n];
int dales[] = new int [2 * n -1];
return backTrack(0,0,n,rows,hills,dales);
}
}
复杂度分析:
时间复杂度:O(n!)
空间复杂度:O(n)
优化:
将数组存储 改为 int 数字 表示 数字15 1111 2^3+2^2+2^1+2^0 表示选中情况 1<<j (1移j位 表示 2^j ) (1<<j ) & s != 0 判断第j个元素 是否在s 里面 (1<<j ) | r 将j位的元素 添加到 r 里面 (1<<j ) | r 表示 行~~~~ (1<<j ) | s1 <<1 表示 / 对角线 (1<<j ) | s2 \>> 1 表示 \\ 对角线
public int cnt;
public int n;
//
public void dfs( int dep ,int r, int s1, int s2){
if (dep == n) {
cnt++;
return;
}
for( int i=0; i<n; i++){
int j= 1<<i; // 当前位置
if( ( (j&r) !=0) || ((j&s1) !=0) || ((j&s2) !=0)) { continue; };
dfs(dep+1, (j|r),(j|s1)<<1, ( j|s2)>>1) ;
// 回溯 ?
}
}
int totalNqueens(int n){
cnt =0;
this.n = n;
dfs(0,0,0,0);
return cnt;
}
}```
对于N皇后搜索问题,在网上也有多种解法,主流是 回溯法(另有衍生的位运算变种算法),
但不管如何优化,回溯法都有一个致命的问题:M值不能过大(一般M=30已是极限)。
还有复杂度更底的解法吗?当然有!
时间复杂度O(1)
早在1969年, 被E. J. Hoffman、J. C. Loessi 和R. C. Moore找到了潜在的数学规律,通过推导出数学公式,利用 构造法 使得该问题可在O(1) 的时间复杂度得到解。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。