编程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;
}

posted on 2021-09-05 09:31  开心种树  阅读(41)  评论(0编辑  收藏  举报