알고리즘 설계 및 분석 최종 요약

0000 서문: 기본적으로 내가 잊기 쉬운 몇 가지를 읽고, 시험을 준비하기 위해, 주로 지식의 후반부, 전반부의 경우, 알고리즘 설계 및 분석 단계 시험의 요약을 참조하십시오 .

5장

역추적 알고리즘은 문제에 대한 솔루션을 체계적으로 검색하는 방법입니다. 문제의 가능한 모든 솔루션을 문제의 솔루션 공간이라고 하며 솔루션 공간이 제한되어 있으면 솔루션 공간을 트리 구조 로 매핑할 수 있습니다 . 역추적 알고리즘의 기본 아이디어는 다음과 같습니다. 한 도로에서 앞으로 가고, 할 수 있으면 전진하고, 할 수 없으면 돌아가고, 다른 길을 시도하십시오.

관련 개념 1

  • 확장 노드
  • 슬립 노드
  • 죽은 노드

관련 개념 2

  • 부분집합 트리: 부분집합 트리를 순회하려면 O(2n) 계산 시간이 필요합니다.
  • 순열 트리: 순열 트리를 순회하려면 O(n!) 계산 시간이 필요합니다.

6장

분기 및 경계 방법은 최적화 문제를 해결하기 위한 알고리즘으로, 일반적으로 폭 우선 또는 최소 비용(최대 이익) 우선 방식으로 문제의 솔루션 공간 트리를 검색합니다 . 기본 아이디어는 문제의 실행 가능한 솔루션을 확장한 다음 각 지점에서 최상의 솔루션을 찾는 것입니다 .

분기 및 결합 방법에서 분기는 너비 우선 전략을 사용하여 확장 노드의 모든 분기를 차례로 생성하는 것입니다. 한계는 노드 확장 과정에서 노드의 상한을 계산하고 검색하는 동안 일부 분기를 잘라냅니다.


역추적과의 차이점

솔루션 목표가 다릅니다.

  • 역추적 방법은 제약 조건을 만족하는 모든 솔루션을 찾는 것입니다.
  • Branch and bound 방법은 조건을 만족하는 솔루션, 또는 어떤 의미에서 최적의 솔루션을 찾는 것입니다.

다르게 검색

  • 역추적: 깊이 우선
  • 분기 및 경계 방법: 폭 우선 또는 최소 비용 우선

관련 개념

  • 슬립 노드
  • 라이브 노드 테이블 PT
  • 확장 노드
  • 아들 노드
  • 대기 중인 분기 및 바운드
  • 우선순위 큐 분기 및 경계

제7장

무작위화 알고리즘은 크게 네 가지 범주로 나뉩니다.

  • 수치 무작위화 알고리즘
  • 몬테카를로 알고리즘
  • 라스베가스 알고리즘
  • 셔우드 알고리즘

무작위화 알고리즘에 대한 입력

  • 원래 문제에 입력
  • 무작위로 선택된 일련의 난수

수치 확률 알고리즘은 종종 수치 문제를 해결하는 데 사용됩니다. 이러한 알고리즘은 종종 근사해를 구하며 근사해의 정확도는 계산 시간이 증가함에 따라 증가합니다. 많은 경우 문제의 정확한 솔루션을 계산하는 것이 불가능하거나 불필요하며 수치 과세 기준 알고리즘을 사용하여 상당히 만족스러운 솔루션을 얻을 수 있습니다.

수치 문제는 일반적으로 다양한 적분 및 미분, 수학적 계산에 사용됩니다.

Monte Carlo 알고리즘은 문제의 정확한 솔루션을 찾는 데 사용됩니다. 많은 문제에서 근사해는 의미가 없습니다. Monte Carlo 알고리즘으로 문제에 대한 해결책을 찾을 수 있지만 솔루션이 올바르지 않을 수 있습니다. 올바른 솔루션을 찾을 확률은 알고리즘에 걸리는 시간에 따라 다릅니다. 알고리즘에 더 많은 시간이 소요될수록 올바른 솔루션을 얻을 확률이 높아집니다. Monte Carlo 알고리즘의 주요 단점도 여기에 있습니다. 일반적으로 얻은 솔루션이 결정 가능하고 올바른지 여부를 효과적으로 판단하는 것은 불가능합니다. (일반적이지 않은 경우도 판단 가능!)

Las Vegas 알고리즘은 잘못된 솔루션을 얻지 않습니다. Las Vegas 알고리즘을 사용하여 솔루션을 찾으면 올바른 솔루션이어야 합니다. 그러나 때로는 Las Vegas 알고리즘이 솔루션을 찾을 수 없습니다. Las Vegas 알고리즘이 올바른 솔루션을 찾을 확률은 계산 시간이 증가함에 따라 증가합니다.

Sherwood 알고리즘은  항상 문제에 대한 올바른 솔루션을 찾을 수 있으며 알고리즘의 최악의 동작과 특정 인스턴스 사이의 상관 관계를 제거해도 평균 성능이 향상되지 않으며 알고리즘의 최악의 동작을 의도적으로 피하지도 않습니다.

지침

  • 무작위화 알고리즘의 결과가 정확하다고 보장할 수는 없지만 오류 확률은 제한될 수 있습니다.
  • 무작위화 알고리즘은 다른 실행에서 동일한 입력 인스턴스에 대해 다른 결과를 가질 수 있으므로 무작위화 알고리즘의 실행 시간은 동일한 입력 인스턴스에 대해 다를 수 있습니다.

알고리즘 분석

역추적

배치 작업 예약(추측)

n개의 작업 집합 {J1,J2,...,Jn}이 주어집니다. 각 작업은 머신 1에서 먼저 처리한 다음 머신 2에서 처리해야 합니다. 작업 Ji는 머신 j에서 처리 시간 tij가 필요합니다. 명확한 작업 일정을 위해 Fij를 작업 i가 머신 j에서 처리를 완료하는 시간이라고 합니다. 기계 2의 모든 작업 처리 시간의 합을 작업 일정 완료 시간의 합이라고 합니다. 배치 작업 스케줄링 문제는 주어진 n개의 작업에 대해 완료 시간의 합을 최소화하기 위해 최상의 작업 스케줄링 체계를 공식화해야 합니다.

N 이후의 질문(생략)

n×n 격자판에 서로 공격받지 않는 n명의 여왕을 배치합니다. 체스 규칙에 따르면 여왕은 여왕과 같은 행이나 열 또는 같은 대각선에 있는 기물을 공격할 수 있습니다. n-퀸 문제는 n×n 그리드에 n개의 퀸을 배치하는 것과 동일하며 두 개의 퀸은 동일한 행이나 열 또는 동일한 슬래시에 배치되지 않습니다. n = 1 또는 n ≥ 4인 경우에만 문제에 해가 있습니다.

생각의 기차

네 가지 사후 문제 해결 방법

기호 삼각형 문제(생략)

 생각의 기차

n-튜플 x[1:n]을 사용하여 기호 삼각형의 첫 번째 행 n개의 기호를 나타냅니다. x[i]가 1이면 기호의 첫 번째 행의 i번째 기호가 삼각형은 "+"이고 x일 때 [i]가 0일 때 기호 삼각형의 첫 번째 행에 있는 i번째 기호는 "-"이고 1<=i<=n입니다. x[i]는 2값이기 때문입니다. 따라서 역추적 방법을 사용하여 기호 삼각형 문제를 풀 때 완전한 이진 트리를 사용하여 솔루션 공간을 나타낼 수 있습니다. 심볼 삼각형의 첫 번째 행에서 첫 번째 i개의 심볼 x[1:i]가 결정된 후, i*(i+1)/2개의 심볼로 구성된 심볼 삼각형이 결정된다.

(i*(i+1)/2는 첫 번째 항목이 1이고 허용오차가 1인 등차의 합 공식에서 나옵니다.)

 풀 수 없는 판단: n*(n+1)/2는 홀수

0-1 배낭 문제

 연습: 0-1 배낭 문제의 예는 다음과 같습니다. n=4, c=16, p=[22,21,16,7], w=[11,10,8,7]. 역추적 방법에 따라 이 문제를 해결하려면 다음 질문에 답해 보십시오.

(1) 이 문제에 대한 제약 함수는 무엇입니까?

(2) 최적의 솔루션을 찾기 위한 솔루션 공간 트리를 그려주세요. 중간에 폐기해야 하는 노드(제약 조건을 충족하지 않는 솔루션)는 ×로 표시하고 중간 솔루션을 얻는 노드는 단일 원 ○으로 표시하고 최적 솔루션은 이중 원 ◎로 표시합니다.

대답: (1) 제약 함수는 ∑wixi≤C입니다. 즉, 배낭에 항목을 담을 수 있습니다.

(2) 솔루션 공간 트리는 아래 그림과 같습니다.

가장 큰 그룹 운동(추측)

 실행 가능성 제약 기능: 현재 정점에서 선택된 정점 세트까지의 모든 정점은 모서리로 연결됩니다.

(2) 경계 기능: 알고리즘이 오른쪽 하위 트리에서 더 큰 클리크를 찾을 수 있도록 충분한 선택적 정점이 있습니다.

가지와 경계

0-1 배낭 문제

0-1 배낭 문제의 다음 인스턴스를 고려하십시오: n=3, c=30, w=[16,15,15], v=[45,25,25]

가지와 경계

여행하는 세일즈맨 문제 (동일한 아이디어는 PPT에만 담았습니다) (생략)

대기 중인 분기 및 바운드

우선순위 큐 분기 및 경계

로드 문제는 동일합니다.

대기 중인 분기 및 바운드

우선순위 큐 분기 및 바운드 방법 (추측)

이 예제를 해결하기 위해 우선 순위 큐의 분기 및 경계 방법이 주어지면 라이브 노드 테이블의 변경 프로세스(우선 순위는 현재 선박에 있는 컨테이너의 무게에 나머지 컨테이너의 무게를 더한 값임)입니다. 설명 방법: [A,B,C]FGF(40), 여기서 [A,B,C]는 활성 노드 테이블, A는 현재 확장된 노드, FG는 A에 의해 생성되고 G는 조건을 충족하지 않습니다. 제약 조건이 차단되고 40은 노드 F의 우선 순위를 의미합니다. 

배선 문제 의 예

무작위화 알고리즘

난수  캐스팅 포인트 방법 으로 유한 적분 계산

몬테카를로 무작위화 알고리즘

프로그램 작성

역추적

로딩 문제

문제 설명

컨테이너 i의 무게가 wi이고 ∑wi ≤ C1+C2인 적재물 C1과 C2로 각각 2척의 선박에 적재될 n개의 컨테이너 배치가 있습니다. load this 컨테이너는 2척의 선박에 적재되었습니다. 그렇다면 로딩 방식을 찾으십시오. 주어진 선적 문제에 해결책이 있는 경우 다음 전략을 채택하여 최적의 선적 체계를 얻을 수 있음을 쉽게 증명할 수 있습니다: (1) 먼저 첫 번째 배를 가능한 한 가득 채웁니다. 두 번째 배 배.

문제 분석

키 코드

// 搜索到叶子节点
    if (i > n) {
        // 如果找到更优解,则更新最优解
        if (cw > bestw) {
            bestw = cw;
            for (int j = 1; j <= n; j++) {
 
                best[j] = x[j];
            }
        }
        return;
    }
    // 搜索左子树
    r -= w[i];
    if (cw + w[i] <= c) {
        x[i] = 1;
        cw += w[i];
        backtrack(i + 1);
        cw -= w[i];
    }
    r += w[i];
    // 搜索右子树
    if (cw + r > bestw) {
        x[i] = 0;
        backtrack(i + 1);
    }



자세한 코드

#include <stdio.h>
#define MAX_N 20
 
int n;                      // 货物数量
int c;                      // 车的载重量
int w[MAX_N],x[MAX_N];               // 每个货物的重量
int best[MAX_N];            // 最优解
int cw;                     // 当前载重量
int bestw;                  // 最优载重量
int r;                      // 剩余物品重量和
 
// 搜索装载方案
void backtrack(int i)
{
    // 搜索到叶子节点
    if (i > n) {
        // 如果找到更优解,则更新最优解
        if (cw > bestw) {
            bestw = cw;
            for (int j = 1; j <= n; j++) {
 
                best[j] = x[j];
            }
        }
        return;
    }
    // 搜索左子树
    r -= w[i];
    if (cw + w[i] <= c) {
        x[i] = 1;
        cw += w[i];
        backtrack(i + 1);
        cw -= w[i];
    }
    r += w[i];
    // 搜索右子树
    if (cw + r > bestw) {
        x[i] = 0;
        backtrack(i + 1);
    }
}
 
int main()
{
    //printf("请输入货物数量和车的载重量(用空格分隔):\n");
    scanf("%d%d", &n, &c);
    //printf("请输入每个货物的重量:\n");
    for (int i = 1; i <= n; i++) {
        scanf("%d", &w[i]);
        r += w[i];
    }
    backtrack(1);
    printf("最优装载方案为:\n");
    for (int i = 1; i <= n; i++) {
        if (best[i]) {
            printf("%d ", i);
        }
    }
    printf("\n最优载重量为:%d\n", bestw);
    return 0;
}

0-1 백팩 ( PPT가 못생기고 물빠짐, 시험용으로 추천 · 다음 코드)

PPT 코드는 블로그 Backtracking Algorithm Design Experiment를 참조하십시오.

키 코드는 어디에


int bound(int t)
{
    int cleft = C - CurWeight;//剩余容量
    int b = CurValue;//现阶段背包内物品的价值
    while (t <= n && w[t] <= cleft)//以物品重量价值递减装入物品
    {
        cleft = cleft - w[t];
        b = b + v[t];
        t++;
    }
    if (t <= n)//装满背包
        b = b + v[t] * cleft / w[t];//计算t号物品的单位价值装满剩余空间
    return b;
}
void backtrack(int t)
{
    if (t > n)//到达叶子节点了
    {
        if (CurValue > BestValue)//已经搜寻完一次了,把现有的最大值赋值;
        {
            BestValue = CurValue;
            for (int i = 1; i <= n; i++)
                BestX[i] = X[i];
        }
        return;
    }
    if (CurWeight + w[t] <= C)//不到背包最大容量进入左子树
    {
        X[t] = 1;//记录是否装入
        CurWeight += w[t];
        CurValue += v[t];
        backtrack(t + 1);//回溯
        CurWeight -= w[t];
        CurValue -= v[t];
    }
    if (bound(t + 1) > BestValue)//进入右子树
    {
        X[t] = 0;//他自己没有后面物品合适
        backtrack(t + 1);//判断
    }
}


 문제 설명

n개의 아이템이 있고 각각의 부피와 가치가 있습니다 주어진 용량의 배낭으로 배낭에 적재된 아이템의 총 가치를 극대화하는 방법은 무엇입니까?
참고 : 일반 배낭 문제와 달리 0-1 배낭 문제에서는 항목이 전체적으로 나타나며 배낭에 전체를 넣거나 전체를 넣지 않는 것만 선택할 수 있습니다.

#include <stdio.h>
#include <stdlib.h>
#define N 100
int n, c, maxValue = 0; // 物品数量,背包容量,最大价值
int w[N], v[N]; // 物品重量,物品价值
int path[N];
int path0[N];
void backtrack(int i, int res, int value) {
    if (i == n) {
        if (value > maxValue) {
                maxValue = value;
                for (int i = 0; i < n; i++) path0[i] = path[i];
        }
        return;
    }
    path[i] = 1;
    if (res >= w[i]) {
            backtrack(i + 1, res - w[i], value + v[i]); // 考虑第i个物品放入背包
    }
    path[i] = 0;
    backtrack(i + 1, res, value); // 不考虑第i个物品放入背包
}
 
int main() {
    scanf("%d%d", &n, &c);
    for (int i = 0; i < n; i++) scanf("%d%d", &w[i], &v[i]);
    backtrack(0, c, 0);
    printf("%d\n", maxValue);
    for (int i = 0; i < n; i++) printf("%d ", path0[i]);
    return 0;
}

여행하는 외판원 문제(생략)

문제 분석

 자세한 코드

#include <stdio.h>
#include <stdbool.h>
#define MAXN 100 // 最大城市数
 
int n;             // 城市数
int graph[MAXN][MAXN]; // 图的邻接矩阵
int path[MAXN],bestPath[MAXN];    // 保存当前路径
bool visited[MAXN]; // 标记城市是否访问过
int minDist = 0x7fffffff; // 保存最短路径的长度
 
void backtracking(int cur, int dist) {
    if (cur == n) {  // 所有城市都已经走过了
        if (dist + graph[path[n - 1]][0] < minDist) {
            minDist = dist + graph[path[n - 1]][0]; // 更新最短路径
            for(int i = 0;i < n;i++){
                bestPath[i] = path[i];
            }
        }
        return;
    }
    for (int i = 1; i < n; i++) { // 枚举下一个城市
        if (!visited[i]) {        // 如果这个城市还没有访问过
            path[cur] = i;         // 选择这个城市
            visited[i] = true;     // 标记这个城市已经访问过
            backtracking(cur + 1, dist + graph[path[cur - 1]][i]); // 递归到下一层
            visited[i] = false;    // 回溯,撤销选择
        }
    }
}
 
int main() {
    scanf("%d", &n); // 输入城市数
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d", &graph[i][j]); // 输入邻接矩阵
        }
    }
    path[0] = 0;       // 起点是城市0
    visited[0] = true; // 标记起点已经访问过
    backtracking(1, 0); // 从第2个城市开始递归
    printf("%d\n", minDist); // 输出最短路径长度
    for(int i = 0;i < n;i++){
        printf("%d ",bestPath[i]+1);
    }
    return 0;
}

 0-1 배낭

 

가지와 경계

로딩 문제

// 定义MaxLoading子函数,用来求解装载问题
// 输入参数:w是一个整型数组,表示集装箱的重量;c是一个整型变量,表示船舶的载重量;n是一个整型变量,表示集装箱的数量;bestx是一个整型数组,用来存储最优解方案
// 返回值:bestw是一个整型变量,表示最优解值
int MaxLoading(int* w, int c, int n, int* bestx) {
    // 初始化变量
    int i = 1; // 当前扩展节点所在层次
    int j; // 循环计数器
    int bestw = 0; // 最优解值
    Heap h; // 优先队列
    h.length = 0; // 优先队列的长度初始化为0
    int* r = new int[n + 1]; // 剩余集装箱重量之和
    r[n] = 0;
    for (j = n - 1; j > 0; j--)
        r[j] = r[j + 1] + w[j + 1];
    Node* p = new Node; // 当前扩展节点
    p->weight = 0;
    p->level = i;
    p->parent = NULL;
    Node* q; // 新生成节点

    while (i != n + 1) { // 当还未到达叶子节点时循环
        if (p->weight + w[i] <= c) { // 进入左子树,即选择第i个集装箱
            q = new Node; // 创建新节点
            q->LChild = 1; // 标记为左子树
            q->level = p->level + 1; // 层次加一
            q->parent = p; // 父节点指向当前扩展节点
            q->weight = p->weight + w[i]; // 节点重量等于父节点重量加上第i个集装箱重量
            q->uweight = q->weight + r[i]; // 节点上界等于节点重量加上剩余集装箱重量之和
            if (q->level == n + 1 && q->weight > bestw) { // 找到更好解
                bestw = q->weight; // 更新最优解值
                for (j = n; j > 0; j--) { // 更新最优解方案
                    bestx[j] = q->LChild;
                    q = q->parent;
                }
            }
            else { // 将新生成节点插入优先队列
                HeapInsert(h, q);
            }
        }
        if (p->weight + r[i] > bestw) { // 进入右子树,即不选择第i个集装箱,并且满足剪枝条件
            q = new Node; // 创建新节点
            q->LChild = 0; // 标记为右子树
            q->level = p->level + 1; // 层次加一
            q->parent = p; // 父节点指向当前扩展节点
            q->weight = p->weight; // 节点重量等于父节点重量
            q->uweight = q->weight + r[i]; // 节点上界等于节点重量加上剩余集装箱重量之和
            if (q->level == n + 1 && q->weight > bestw) { // 找到更好解
                bestw = q->weight; // 更新最优解值
                for (j = n; j > 0; j--) { // 更新最优解方案
                    bestx[j] = q->LChild;
                    q = q->parent;
                }
            }
            else { // 将新生成节点插入优先队列
                HeapInsert(h, q);
            }
        }
        delete p; // 删除当前扩展节点
        if (!h.empty()) { // 取堆顶元素作为下一个扩展节点,并且堆不为空时继续循环
            HeapDelete(h, p);
            i = p->level;
        }
        else { // 堆为空则结束循环
            break;
        }
        
    }
    delete[] r; // 删除动态数组r
    return bestw; // 返回最优解值
}

최대 파벌 문제

 

0-1 배낭

무작위화

무작위 퀵 정렬: 피벗 포인트를 무작위로 선택하는 퀵 정렬 알고리즘

핵심 코드

void quickSort(int r[], int low, int high)
{
	srand(time(0));
	int i, k;
	if (low<high)
	{
		i=randomNum(low, high); //在区间[low,high]中随机选取一个元素,下标为i
		r[low]←→r[i]; //交换r[low]和r[i]的值
		k=partition(r, low, high); //进行一次划分,得到轴值的位置k
		quickSort(r, low, k-1);//在前半部分继续查找
		quickSort(r, k+1, high);//在后半部分继续查找
	}
}

전체 코드

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
//舍伍德(Sherwood)型随机化算法 随机快速排序:随机选择枢点的快速排序算法
 
//在区间[low,high]中随机选取一个元素,下标为i
int randomNum(int low, int high){
  return low + rand() % (high - low + 1);
}
 
//交换两个元素的值
void swap(int *a, int *b){
  int temp = *a;
  *a = *b;
  *b = temp;
}
 
//进行一次划分,得到轴值的位置k
int partition(int r[], int low, int high){
  int pivot = r[low]; //选取第一个元素作为轴值
  while(low < high){ //循环直到low和high相遇
    while(low < high && r[high] >= pivot) high--; //从右向左找到第一个小于轴值的元素
    swap(&r[low], &r[high]); //交换r[low]和r[high]的值
    while(low < high && r[low] <= pivot) low++; //从左向右找到第一个大于轴值的元素
    swap(&r[low], &r[high]); //交换r[low]和r[high]的值
  }
  return low; //返回轴值的位置
}
 
//快速排序函数
void quickSort(int r[], int low, int high)
{
	srand(time(0));
	int i, k;
	if (low<high)
	{
		i=randomNum(low, high); //在区间[low,high]中随机选取一个元素,下标为i
		swap(&r[low], &r[i]); //交换r[low]和r[i]的值
		k=partition(r, low, high); //进行一次划分,得到轴值的位置k
		quickSort(r, low, k-1);//在前半部分继续查找
		quickSort(r, k+1, high);//在后半部分继续查找
	}
}
 
//打印数组
void printArray(int arr[], int n){
  int i;
  for(i=0; i<n; i++){
    printf("%d ", arr[i]);
  }
  printf("\n");
}
 
//主函数
int main(){
  //定义一个数组,表示10个待排序的数
  int arr[10] = {23, 45, 12, 67, 89, 34, 56, 78, 90, 11};
  //打印原始数组
  printf("原始数组:\n");
  printArray(arr, 10);
  //调用快速排序函数
  quickSort(arr, 0, 9);
  //打印排序后的数组
  printf("排序后的数组:\n");
  printArray(arr, 10);
 
  return 0;
}

여덟 여왕 문제 (ppt에는 코드가 없어서 테스트 확률이 높지 않은 것 같습니다)

(1) 배열 x[8]을 0으로 초기화하고 시도 횟수를 0으로 초기화합니다.

(2) for (i=1; i<=8; i++)     

 2.1 [1, 8]의 난수 j를 생성합니다.   

 2.2 카운트=카운트+1, 카운트 시행;     

 2.3 여왕 i(i행에 고정됨)가 충돌 없이 j열에 배치되면 x[i]=j, count=0, 단계 (2)로 이동하여 다음 여왕을 배치합니다(for 루프가 계속 실행됨).     

  2.4 if (count==8)이면 여왕 i를 배치할 수 없으며 알고리즘이 실패합니다.       

 2.1단계로 이동하여 여왕 i의 위치를 ​​변경합니다.

(3) 여덟 개의 여왕 문제에 대한 해결책으로 요소 x[1]~x[8]을 출력합니다.

#include <iostream>
#include <cstdlib>
#include <ctime>
 
using namespace std;
 
bool isSafe(int x[], int row, int col) {
    // 检查当前位置是否与之前放置的皇后冲突
    for (int i = 1; i < row; i++) {
        if (x[i] == col || abs(i - row) == abs(x[i] - col)) {
            return false;
        }
    }
    return true;
}
 
void solveEightQueens(int x[], int row) {
    if (row > 8) {
        // 所有皇后都放置完成,打印解
        for (int i = 1; i <= 8; i++) {
            cout << x[i] << " ";
        }
        cout << endl;
    } else {
        for (int j = 1; j <= 8; j++) {
            if (isSafe(x, row, j)) {
                x[row] = j;
                solveEightQueens(x, row + 1);
            }
        }
    }
}
 
int main() {
    srand(time(0));
 
    int x[9] = {0}; // 数组从下标 1 开始使用,初始化为0
 
    solveEightQueens(x, 1);
 
    return 0;
}

코드 출력의 의미는 다음과 같습니다.

  • 각 행은 솔루션, 즉 조건을 만족하는 퀸 배치 체계를 나타냅니다.
  • 각 행에는 8개의 숫자가 있으며 각각 첫 번째 행에서 여덟 번째 행의 여왕의 열 번호를 나타냅니다.
  • 예를 들어, 첫 번째 행의 출력은 4 2 7 3 6 8 5 1입니다. 즉, 첫 번째 행의 여왕은 네 번째 열에 있고 두 번째 행의 여왕은 두 번째 열에 있는 식입니다.
  • 총 92개의 가능한 솔루션, 즉 92개의 서로 다른 여왕 배치 방식이 있습니다.

주요 요소 문제

핵심 코드


bool isMajority(int arr[], int n, int x) {
    int count = 0; // 记录x出现的次数
    for (int i = 0; i < n; i++) {
        if (arr[i] == x) count++;
    }
    return count > n / 2; // 如果x出现次数超过一半,返回true
}

최적화

전체 코드

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
 
// 在区间[low,high]中随机选取一个整数
int randomNum(int low, int high) {
    return low + rand() % (high - low + 1);
}
 
// 判断一个元素是否是主元素,即出现次数超过一半
bool isMajority(int arr[], int n, int x) {
    int count = 0; // 记录x出现的次数
    for (int i = 0; i < n; i++) {
        if (arr[i] == x) count++;
    }
    return count > n / 2; // 如果x出现次数超过一半,返回true
}
 
// 蒙特卡罗函数,返回数组中的一个主元素,如果不存在,返回-1
int monteCarlo(int arr[], int n) {
    srand(time(0)); // 设置随机数种子
    int k = 10; // 设置最大尝试次数
 
    // 候选主元素初始化为数组的第一个元素
    int candidate = arr[0];
    int count = 1; // 记录候选主元素的计数
 
    for (int i = 1; i < n; i++) {
        if (arr[i] == candidate) {
            count++;
        } else {
            count--;
            if (count == 0) {
                // 当前候选主元素计数为0,更新候选主元素为当前元素
                candidate = arr[i];
                count = 1;
            }
        }
    }
 
    // 最后确定的候选主元素需要再次验证
    if (isMajority(arr, n, candidate)) {
        return candidate; // 如果是,返回该元素
    }
 
    return -1; // 如果不存在主元素,返回-1
}
 
// 打印数组
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}
 
// 主函数
int main() {
    // 定义一个数组,表示n个待查找的数
    int arr[10] = {3, 3, 4, 4, 2, 4, 2, 4, 4,4};
 
    // 打印原始数组
    cout << "原始数组:\n";
    printArray(arr, 10);
 
    // 调用蒙特卡罗函数,返回数组中的一个主元素
    int result = monteCarlo(arr, 10);
 
    // 打印结果
    if (result == -1) {
        cout << "不存在主元素" << endl;
    } else {
        cout << "一个主元素是:" << result << endl;
    }
 
    return 0;
}

추천

출처blog.csdn.net/qq_62377885/article/details/130832631