算法实现总结 - C/C++

算法实现 - C/C++

  • 前言
  • [1. 数据结构类](#1. 数据结构类)
  • [2. 常见算法类](#2. 常见算法类)
    • [2.1 n皇后](#2.1 n皇后)
  • 参考文献

前言

总结积累平时研究的算法,不定时更新,便于形成体系。

积累习惯:

  1. 一张图形象描述问题
  2. 该算法触动/记忆点
  3. 算法策略(分递二,回贪动)
  4. 算法代码含关键理解点

1. 数据结构类

2. 常见算法类

2.1 n皇后

25年下半年软考算法题。

当时脑子里只有queen[i][j]的二维解法,案例使用k表行,queen[k]表列时有点懵(没这个概念)。虽然跌跌撞撞写出了大部分,但主要是题目引导和举实例试出来的。

策略:回溯法

法一: 案例解法

c 复制代码
#include<stdio.h>
#include<math.h>
#define N 100			// 最多摆放100个皇后 
int n,queen[N];			// 关键理解:queen[k] 表示 "第 k 行的皇后放在第queen[k]列"(行和列均从 0 开始计数)。
						// 例如:queen[0] = 1 表示第 0 行的皇后在第 1 列。
						// 这种设计天然避免了 "同一行多个皇后" 的冲突(因为每行只存一个列号)。
int num = 0;			// 总共有多少方案

void Putqueen(int k)	// 假设前k个皇后已经摆好,现在摆放第K个皇后
{
	int i,j;
	if(k==n)			// 终止条件:第 0 到第 n-1 行的皇后都已摆放完成(共 n 行,即所有皇后都放好了)。
	{
		for(i=0;i<n;i++)
		{
			printf("(%d,%d)\t",i+1,queen[i]+1);		// 输出时 i+1 和 queen[i]+1 是将 "0 开始的索引" 转换为 "1 开始的棋盘坐标"(符合日常习惯)。
		}
		printf("\n");
		num ++;
	}
	else
	{
		for(i=0;i<n;++i)		// 尝试将第k行皇后放在第i列 (同一行一例一列试)
		{
			for(j=0;j<k;++j)	// 检查当前位置(i列)与前k行皇后是否冲突
			{
				if(i==queen[j]||abs(queen[j]-i)==abs(j-k))		// 冲突条件:同列 或 同对角线
				{
					break;		//有冲突,跳出检查,尝试下一列
				}
			}
			if(j==k)			// 前k行都无冲突(当前列i合法)
			{
				queen[k]=i;		// 记录第k行皇后在第i列
				Putqueen(k+1);	// 递归摆放下一行(第k+1行)
			}	
		}
	}
	
}

int main()
{
	scanf("%d",&n);			// 输入皇后数量n
	Putqueen(0);			// 从第0行开始摆放皇后
	printf("num: %d\n\n", num);			// 输出方案数量
	return 0;	
}

法二:法一上优化冲突检查方式

空间换时间,尤其适合求解较大 n 的问题.

c 复制代码
#include<stdio.h>
#include<math.h>
#define N 100			    //最多摆放100个皇后 
int n;
int queen[N];
int visited[3][2*N-2];      // visited数组:记录列、主对角线、副对角线是否被占用
                            // 其中:
                            // visited[0][i]:标记第i列是否有皇后(列冲突)
                            // visited[1][k+i]:标记主对角线(k+i为定值)是否有皇后(主对角线冲突)
                            // visited[2][k-i+n]:标记副对角线(k-i为定值,加n避免负数索引)是否有皇后(副对角线冲突)

/*
    核心思路:用visited数组提前记录 "已被皇后占用的列和对角线",每次检查冲突时无需遍历前 k 行,直接通过 3 个索引判断:
        列冲突:第 i 列是否被占用(visited[0][i]);
        主对角线冲突:对于第 k 行第 i 列,主对角线的特征是 "行 + 列 = k+i"(同一主对角线上的所有位置,行 + 列的值相同),因此用visited[1][k+i]标记;
        副对角线冲突:对于第 k 行第 i 列,副对角线的特征是 "行 - 列 = k-i"(同一副对角线上的所有位置,行 - 列的值相同),但k-i可能为负数,因此加 n(偏移量)避免数组索引为负,用visited[2][k-i+n]标记。
    操作:摆放皇后时,将对应的列、主对角线、副对角线标记为 "占用"(置 1);回溯时(递归返回后),再重置为 "未占用"(置 0),确保不影响其他分支的尝试。
*/
void Putqueen(int k)
{
	int i,j;
	if(k==n)		    //递归出口 
	{
		for(i=0;i<n;i++)
			printf("(%d,%d)\t",i+1,queen[i]);
		printf("\n");
	}
	else
	{
		for(i=0;i<n;i++)        // 检查第k行第i列是否与前k行皇后冲突
		{
			if(!visited[0][i]&&!visited[1][k+i]&&!visited[2][k-i+n])	//k-i可能为负,所以加n 
			{
				queen[k]=i;
				visited[0][i]=visited[1][k+i]=visited[2][k-i+n]=1;
				Putqueen(k+1);
				visited[0][i]=visited[1][k+i]=visited[2][k-i+n]=0;
			}
		}
	}
	
}

int main()
{
	scanf("%d",&n);
	Putqueen(0);
	return 0;	
}

/*
1. 时间效率显著提升:通过 "空间换时间",将冲突检查从 O (k) 优化为 O (1),总时间复杂度从O(n! * n²)降至O(n!),尤其在 n 较大时(如 n=12 以上),运行速度会明显更快。
2. 空间开销可控:虽然增加了visited数组,但空间复杂度仍为 O (n),没有本质增加,属于 "用少量空间换大幅时间优化" 的典型做法。
*/

参考文献

  1. n 皇后:https://blog.csdn.net/weixin_45953673/article/details/104468683
相关推荐
zmzb01039 分钟前
C++课后习题训练记录Day43
开发语言·c++
月明长歌18 分钟前
【码道初阶】一道经典简单题:多数元素(LeetCode 169)|Boyer-Moore 投票算法详解
算法·leetcode·职场和发展
wadesir23 分钟前
C语言模块化设计入门指南(从零开始构建清晰可维护的C程序)
c语言·开发语言·算法
t1987512827 分钟前
MATLAB水声信道仿真程序
开发语言·算法·matlab
赖small强34 分钟前
【Linux C/C++开发】 GCC -g 调试参数深度解析与最佳实践
linux·c语言·c++·gdb·-g
CAE虚拟与现实1 小时前
C/C++中“静态链接(Static Linking)” 和 “动态链接(Dynamic Linking)释疑
开发语言·c++·dll·动态链接库·lib库
fpcc1 小时前
C++编程实践——标准库中容器存储目标分析
c++
包饭厅咸鱼1 小时前
PatchCore-----训练,测试,c++部署 工业异常检测框架
开发语言·c++·视觉检测
许长安2 小时前
C++ 多态详解:从静态多态到动态多态
开发语言·c++·经验分享·笔记
猫猫的小茶馆2 小时前
【ARM】ARM的介绍
c语言·开发语言·arm开发·stm32·单片机·嵌入式硬件·物联网