编程117
1. 用蒙特卡洛方法计算PI
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int tosses, cir_nb, i;
double dub_x, dub_y, dub_r;
srand(time(NULL));
while (1) {
cir_nb = 0;
printf("Enter the number of tosses (2 < N <= 1000000) \n");
scanf("%d", &tosses);
if (tosses < 2 || tosses > 1000000)
continue;
for (i = 0; i < tosses; i++) { // 投掷 tosses 次
dub_x = (double)random()/RAND_MAX;
dub_y = (double)random()/RAND_MAX;
dub_r = sqrt(dub_x * dub_x + dub_y * dub_y); // 计算随机点是否落在圆内
if (dub_r <= 1) {
cir_nb++;
}
}
double pi = 4 * (double)cir_nb / tosses; // 因为 随机点落在圆和正方形的概率 和 面积等比
printf("PI : %f\n", pi);
}
return 0;
}
2. 用埃拉托斯特尼筛法求质数
#include <stdio.h>
#include <math.h>
#include <alloca.h>
#include <stdlib.h>
void prime(int *arr, int i, int n)
{
int j, a;
a = arr[i];
for (j = i+1; j < n; j++) {
if (arr[j] != 0 && (arr[j] % a) == 0) {
arr[j] = 0;
}
}
}
void test(int n)
{
int i, arr[n];
double limit;
limit = sqrt((double)n);
for (i = 1; i < n; i++) {
arr[i] = i;
}
arr[1] = 0; // 1 是质数
for (i = 2; i < n; i++) {
if (arr[i] > limit) {
break;
}
if (arr[i] != 0) {
prime(arr, i, n); // 删除 arr[i] 的倍数
}
}
printf("prime :\n");
for (i = 1; i < n; ++i) {
if (arr[i] != 0) {
printf("%d ", arr[i]);
}
}
}
int main(int argc, char *argv[])
{
int n;
while (1) {
printf("Enter the number (1 <= N <= 100000)\n");
scanf("%d", &n);
if (n < 1 || n > 100000)
continue;
test(n+1);
}
return 0;
}
3.汉诺塔
思路:
比如有 SRC : 1 2 3
则应该把 1 2 放到 TMP
把 3 放到 DST。
即把放 1 2 3,放 1 2。
同理 把 放 1 2 ,简化为 放 1
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <alloca.h>
#include <stdlib.h>
typedef struct {
char *name;
int *head;
int size;
int *arr;
} tower_t;
#define init_tower(t, n, str) do{ \
t.size = 0; \
t.arr = (int *)malloc(sizeof(int) * n + 1); \
t.head = (int *)t.arr + n; \
t.name = str; \
} while(0)
int g_nb;
int *g_a;
int *g_b;
int *g_c;
void display()
{
printf("------------------\n");
printf("SRC: ");
for (int i = 0; i < g_nb; i++) {
printf("%d ", g_a[i]);
}
printf("\n");
printf("DST: ");
for (int i = 0; i < g_nb; i++) {
printf("%d ", g_b[i]);
}
printf("\n");
printf("TMP: ");
for (int i = 0; i < g_nb; i++) {
printf("%d ", g_c[i]);
}
printf("\n");
}
// 借助 tmp,把 src 元素 放到 dst
void move(tower_t *src, tower_t *dst, tower_t *tmp)
{
int tmp_sz;
if (src->size == 1) { // 只有一个元素,直接放, 同时递归返回
printf("%s:%d -> %s\n", src->name, *src->head, dst->name);
dst->head--;
*dst->head = *src->head;
*src->head = 0;
src->head++;
dst->size++;
src->size--;
display();
}
else {
// 把 src 上层元素放到 tmp
src->size--;
tmp_sz = src->size;
move(src, tmp, dst);
// src只剩一个元素,直接放到dst
printf("%s:%d -> %s\n", src->name, *src->head, dst->name);
dst->head--;
dst->size++;
*dst->head = *src->head;
*src->head = 0;
src->head++;
display();
// 把零时存放在 tmp的元素放到 dst
tmp->size = tmp_sz;
move(tmp, dst, src);
}
}
void test(int n)
{
tower_t a, b, c;
int i;
// 准备塔
init_tower(a, n, "SRC");
init_tower(b, n, "DST");
init_tower(c, n, "TMP");
for (i = n; i > 0; i--) {
a.head--;
*a.head = i;
a.size++;
}
memset(b.arr, 0x0, b.size * sizeof(int));
memset(c.arr, 0x0, c.size * sizeof(int));
g_nb = n;
g_a = a.arr;
g_b = b.arr;
g_c = c.arr;
// 放塔
move(&a, &b, &c);
}
int main(int argc, char *argv[])
{
int n;
printf("Enter the number\n");
scanf("%d", &n);
test(n);
return 0;
}
4. 八皇后
思路:列举所有可能,去除错误
列举可能的方法 利用 递归,如:下第一个棋子,下所有可能情况,除去前面棋子导致的错误(没有前面棋子,所以都是对的),下第二个棋子所有可能,去除前面棋子导致错误...
由于每个棋子不能在同一行,所以限定第i个棋子在第i行,从而裁剪递归树。
理论上还可以找到更多裁剪方法,但那属于数学范畴。
计算机方面来看,八皇后和汉诺塔带给我们的更多是分治思想,也就是把问题分解成最小规模数据量的相同策略解决的问题,分治策略不高效(基本上遍历了问题所有情况),但是计算机速度快,好处是方便告诉计算机怎么做
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <alloca.h>
#include <stdlib.h>
int count;
int chess[9]; // 记录8个棋子下的列数
int is_vaild(int row, int col)
{
int i;
for (i = 1; i < row; i++) { // 本棋子是row行,所以前面的棋子是 [1, row-1]行, 前面棋子的col记录在对应的chess[i]中
if (chess[i] == col) {
return 0;
}
if (abs(row - i ) == abs(col - chess[i])) // 对角线
return 0;
}
return 1;
}
void display(int nb)
{
count++;
int i, j;
printf(" ");
for (i = 1; i <= nb; i++) {
printf(" %d ", i);
}
printf("\n");
for (i = 1; i <= nb; i++) {
printf ("%d ", i);
for (j = 1; j <= nb; j++) {
if (j == chess[i]) {
printf (" q ");
}
else {
printf (" - ");
}
}
printf("\n");
}
}
// 下一个棋子,该棋子在 第row行 找所有可能,nb是棋子总数
void queen(int row, int nb)
{
int col;
for (col = 1; col <= nb ; col++) { // 该棋子可能下的所有点 [col, row]
if (is_vaild(row, col)) {
chess[row] = col; // 记录合法的col
if (row == nb) { // 下完所有棋子
display(nb);
getchar();
return ;
}
queen(row + 1, nb); //下下一个棋子
}
}
}
int main(int argc, char *argv[])
{
queen(1, 8);
printf("count : %d\n", count);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?