算法基础学习笔记——⑬高斯消元\组合计数\容斥原理

news2024/9/29 3:30:46

博主:命运之光
专栏:算法基础学习

在这里插入图片描述

目录

✨高斯消元

✨组合计数

🍓通过预处理逆元的方式求组合数:

🍓Lucas定理:

🍓分解质因数法求组合数:


前言:算法学习笔记记录日常分享,需要的看哈O(∩_∩)O,感谢大家的支持!


✨高斯消元

高斯消元(Gaussian Elimination)是一种用于解线性方程组的算法,通过逐步的行变换来将方程组转化为简化的行阶梯形式,从而求解方程组的解。

🍓以下是一个用C语言编写的高斯消元算法的示例代码:

#include <stdio.h>
#define N 3 // 方程个数和未知数个数
void gaussianElimination(float matrix[N][N + 1], float solution[N]) {
    int i, j, k;
    float factor;

    // 前向消元
    for (i = 0; i < N - 1; i++) {
        for (k = i + 1; k < N; k++) {
            factor = matrix[k][i] / matrix[i][i];
            for (j = i; j < N + 1; j++) {
                matrix[k][j] -= factor * matrix[i][j];
            }
        }
    }
    // 回代求解
    for (i = N - 1; i >= 0; i--) {
        solution[i] = matrix[i][N];
        for (j = i + 1; j < N; j++) {
            solution[i] -= matrix[i][j] * solution[j];
        }
        solution[i] /= matrix[i][i];
    }
}
int main() {
    float matrix[N][N + 1];
    float solution[N];
    int i, j;
    printf("Enter the augmented matrix:\n");
    for (i = 0; i < N; i++) {
        for (j = 0; j < N + 1; j++) {
            scanf("%f", &matrix[i][j]);
        }
    }
    gaussianElimination(matrix, solution);
    printf("Solution:\n");
    for (i = 0; i < N; i++) {
        printf("x%d = %.2f\n", i + 1, solution[i]);
    }
    return 0;
}

在上述代码中,我们定义了gaussianElimination函数来执行高斯消元算法。算法分为两个阶段:前向消元和回代求解。

前向消元阶段通过循环进行逐行消元操作,将方程组转化为行阶梯形式。首先,通过除以主对角线上的元素将当前行的主元素变为1。然后,通过逐行减去当前行的倍数,将当前列下方的元素变为0。

回代求解阶段从最后一行开始,通过回代计算未知数的值。首先,将当前行的右侧常数项赋值给对应的未知数。然后,逐列减去已知未知数的乘积,最后除以当前行的主元素。

在main函数中,我们首先接受用户输入的增广矩阵,其中最后一列为常数项。然后,调用gaussianElimination函数来解方程组,并将结果打印出来。

你可以运行上述代码,根据提示输入增广矩阵,程序将计算并输出方程组的解。


🍓高斯消元 :

// a[N][N]是增广矩阵
int gauss()
{
     int c, r;
     for (c = 0, r = 0; c < n; c ++ )
     {
         int t = r;
         for (int i = r; i < n; i ++ ) // 找到绝对值最大的行
             if (fabs(a[i][c]) > fabs(a[t][c]))
             	t = i;
         if (fabs(a[t][c]) < eps) continue;
         for (int i = c; i <= n; i ++ ) swap(a[t][i], a[r][i]); // 将绝对值最大的行换到最顶端
         for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c]; // 将当前行的首位变成1
         for (int i = r + 1; i < n; i ++ ) // 用当前行将下面所有的列消成0
            if (fabs(a[i][c]) > eps)
                for (int j = n; j >= c; j -- )
                    a[i][j] -= a[r][j] * a[i][c];
         r ++ ;
     }
     if (r < n)
     {
         for (int i = r; i < n; i ++ )
             if (fabs(a[i][n]) > eps)
             	return 2; // 无解
     return 1; // 有无穷多组解
     }
     for (int i = n - 1; i >= 0; i -- )
         for (int j = i + 1; j < n; j ++ )
             a[i][n] -= a[i][j] * a[j][n];
     return 0; // 有唯一解
}

✨组合计数

在C语言中,可以使用动态规划来实现组合计数(Combination Counting)。组合计数用于计算从n个元素中选择k个元素的组合数。

🍓以下是一个用C语言编写的组合计数算法的示例代码:

#include <stdio.h>
// 计算组合数C(n, k)
int combinationCount(int n, int k) {
    int C[n + 1][k + 1];
    int i, j;

    // 基本情况
    for (i = 0; i <= n; i++) {
        for (j = 0; j <= i && j <= k; j++) {
            if (j == 0 || j == i)
                C[i][j] = 1;
            else
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
    }

    return C[n][k];
}
int main() {
    int n, k;
    printf("Enter the values of n and k: ");
    scanf("%d %d", &n, &k);
    int result = combinationCount(n, k);
    printf("Combination Count: %d\n", result);
    return 0;
}

在上述代码中,我们定义了一个combinationCount函数来计算组合数C(n, k)。算法使用动态规划的思想,使用一个二维数组C来存储中间结果。

首先,我们处理基本情况,即当k等于0或k等于n时,组合数C(n, k)为1。然后,通过递推关系C(n, k) = C(n-1, k-1) + C(n-1, k),我们填充C数组的其余元素。

在main函数中,我们接受用户输入的n和k的值,并调用combinationCount函数来计算组合数。然后,我们输出计算结果。

你可以运行上述代码,根据提示输入n和k的值,程序将计算并输出组合数C(n, k)的结果。

请注意,上述代码中的组合计数算法使用了动态规划的方法,对于较大的n和k可能会产生较大的中间结果。在实际应用中,可以使用更高效的算法或数学公式来计算组合数。


🍓递推法求组合数:

// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )
    for (int j = 0; j <= i; j ++ )
        if (!j) c[i][j] = 1;
        else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;

🍓通过预处理逆元的方式求组合数:

首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N]

如果取模的数是质数,可以用费马小定理求逆元

int qmi(int a, int k, int p) // 快速幂模板
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
// 预处理阶乘的余数和阶乘逆元的余数
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
    fact[i] = (LL)fact[i - 1] * i % mod;
    infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}

🍓Lucas定理:

若p是质数,则对于任意整数 1 <= m <= n,有:

C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p)

int qmi(int a, int k, int p) // 快速幂模板
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
	}
	return res;
}
int C(int a, int b, int p) // 通过定理求组合数C(a, b)
{
    if (a < b) return 0;
    LL x = 1, y = 1; // x是分子,y是分母
    for (int i = a, j = 1; j <= b; i --, j ++ )
    {
        x = (LL)x * i % p;
        y = (LL) y * j % p;
    }
    return x * (LL)qmi(y, p - 2, p) % p;
}
int lucas(LL a, LL b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

🍓分解质因数法求组合数:

当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用:

1. 筛法求出范围内的所有质数

2. 通过 C(a, b) = a! / b! / (a - b)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2 + n / p^3 + ...

3. 用高精度乘法将所有质因子相乘

int primes[N], cnt; // 存储所有质数
int sum[N]; // 存储每个质数的次数
bool st[N]; // 存储每个数是否已被筛掉
void get_primes(int n) // 线性筛法求素数
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
int get(int n, int p) // 求n!中的次数
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}
vector<int> mul(vector<int> a, int b) // 高精度乘低精度模板
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}
get_primes(a); // 预处理范围内的所有质数
for (int i = 0; i < cnt; i ++ ) // 求每个质因数的次数
{
    int p = primes[i];
    sum[i] = get(a, p) - get(b, p) - get(a - b, p);
}
vector<int> res;
res.push_back(1);
for (int i = 0; i < cnt; i ++ ) // 用高精度乘法将所有质因子相乘
	for (int j = 0; j < sum[i]; j ++ )
		res = mul(res, primes[i]);

✨容斥原理

在C语言中,可以使用容斥原理(Inclusion-Exclusion Principle)来解决一些计数问题。容斥原理是组合数学中的一个重要原理,用于计算多个集合的并集、交集等情况下的计数问题。

🍓以下是一个用C语言编写的容斥原理算法的示例代码:

#include <stdio.h>

// 计算集合交集的大小
int intersectionSize(int set[], int setSize) {
    int result = set[0];
    for (int i = 1; i < setSize; i++) {
        result &= set[i];
    }
    return result;
}

// 计算集合并集的大小
int unionSize(int set[], int setSize) {
    int result = set[0];
    for (int i = 1; i < setSize; i++) {
        result |= set[i];
    }
    return result;
}

// 计算容斥原理的应用
int inclusionExclusion(int sets[][3], int numSets, int setSize) {
    int result = 0;
    for (int i = 1; i < (1 << numSets); i++) {
        int sign = (__builtin_popcount(i) % 2 == 1) ? 1 : -1;

        int tempSet[setSize];
        for (int j = 0; j < setSize; j++) {
            tempSet[j] = 0;
        }

        for (int j = 0; j < numSets; j++) {
            if (i & (1 << j)) {
                for (int k = 0; k < setSize; k++) {
                    tempSet[k] |= sets[j][k];
                }
            }
        }

        int intersection = intersectionSize(tempSet, setSize);
        result += sign * intersection;
    }
    return result;
}

int main() {
    int sets[3][3] = {
        {1, 2, 3},
        {2, 3, 4},
        {3, 4, 5}
    };
    int numSets = 3;
    int setSize = 3;

    int result = inclusionExclusion(sets, numSets, setSize);
    printf("Result: %d\n", result);

    return 0;
}

在上述代码中,我们定义了三个函数:intersectionSize用于计算集合交集的大小,unionSize用于计算集合并集的大小,inclusionExclusion用于应用容斥原理。

intersectionSize函数通过遍历集合元素并执行按位与操作来计算集合交集的大小。

unionSize函数通过遍历集合元素并执行按位或操作来计算集合并集的大小。

inclusionExclusion函数使用位运算和循环来实现容斥原理的应用。它从空集开始,遍历所有子集,并计算交集的大小。根据子集中元素的数量的奇偶性,确定交集的贡献正负号,并累加到最终结果中。

在main函数中,我们定义了一个包含三个集合的二维数组,并调用inclusionExclusion函数来应用容斥原理计算结果。

你可以运行上述代码,它将输出应用容斥原


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/586615.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【小可爱专属教程】服务器配置环境

【小可爱专属教程】服务器配置环境 安装CUDA和CUDNN安装CUDA安装CUDNN 安装Anaconda3安装Pytorch 安装CUDA和CUDNN 安装CUDA 文件已经上传至百度网盘 链接&#xff1a;https://pan.baidu.com/s/1LKzZXtSr1kXOnlfbO0cmEw?pwdgfbb 提取码&#xff1a;gfbbsudo sh cuda_11.3.…

【技术解决方案】(多级)缓存架构最佳实践

凌晨三点半了&#xff0c;太困了&#xff0c;还差一些&#xff0c;明天补上… 因为自己最近做的项目涉及到了缓存&#xff0c;所以水一篇缓存相关的文章&#xff0c;供大家作为参考&#xff0c;若发现文章有纰漏&#xff0c;希望大家多指正。 缓存涉及到的范围颇广&#xff0c…

spring boot整合Swagger2(2.9.2版本)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

计算机组成原理-中央处理器-指令流水线和多处理器

目录 一、指令流水线基本概念 1.1影响流水线的因素 1.1.1结构相关(资源冲突) 1.1.2 数据相关(数据冲突) 1.1.3 控制相关(控制冲突) 1. 2 流水线分类 二、流水线的多发技术 2.1 超标量技术 2.2 超流水技术 2.3 超长指令字 三、五段式指令流水线 四、多处理器系统基本概念…

I.MX RT1170加密启动详解(1):Encrypted Boot image组成

使用RT1170芯片构建的所有平台一般都是高端场合&#xff0c;我们需要考虑软件的安全需求。该芯片集成了一系列安全功能。这些特性中的大多数提供针对特定类型攻击的保护&#xff0c;并且可以根据所需的保护程度配置为不同的级别。这些特性可以协同工作&#xff0c;也可以独立工…

chatgpt赋能python:Python中的区间:什么是区间(Interval),如何使用区间

Python 中的区间&#xff1a;什么是 区间&#xff08;Interval&#xff09;&#xff0c;如何使用区间 在Python中&#xff0c;区间&#xff08;Interval&#xff09;是一个广泛使用的数据结构&#xff0c;用于表示一段连续的数据范围。使用区间可以更方便地处理各种数据类型&a…

本地搭建CFimagehost私人图床【公网远程访问】

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

代码随想录算法训练营第四十一天 | 力扣 343. 整数拆分, 96.不同的二叉搜索树

343. 整数拆分 题目 343. 整数拆分 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 解析 1.确定dp数组&#xff08;dp table&#xff09;以及下标的…

史上最详细的使用Claude和接入Claude-api教程

是什么&#xff08;What&#xff09; Claude 是最近新开放的一款 AI 聊天机器人&#xff0c;是世界上最大的语言模型之一&#xff0c;比之前的一些模型如 GPT-3 要强大得多&#xff0c;因此 Claude 被认为是 ChatGPT 最有力的竞争对手。Claude 的研发公司是专注人工智能安全和研…

Java制作520表白代码——爱一个人需要理由吗?

✨博主&#xff1a;命运之光 ✨专栏&#xff1a;Java经典程序设计 520表白日&#xff0c;每个人都期待着浪漫的表白&#xff0c;而作为一名热爱编程的程序员&#xff0c;我决定用程序员的方式来向你表达我的爱意。 在2023年5月20日这个特殊的日子里&#xff0c;我要用一段特别的…

BM1684X-onnx模型转化为bmodel

1&#xff1a;在tpu-mlir目录下进入docker docker run --privileged --name tpu-mlir -v $PWD:/workspace -it sophgo/tpuc_dev:v2.2 原因&#xff1a;该镜像已创建&#xff0c;要么重新创建一个新进程&#xff0c;要么杀死老进程&#xff1b; 解决办法如下&#xff1a; 2:接着…

夜深人静学32系列17——OLED

夜深人静学32系列17——OLED OLED简介接口定义OLED驱动原理驱动函数OLED.COLED.HCubeMX配置 实战部分效果展示驱动代码 OLED简介 LED&#xff0c;即有机发光二极管&#xff08;Organic Light-Emitting Diode&#xff09;&#xff0c;又称为有机激光显示&#xff08;Organic El…

基于YOLOV5的道路损伤(GRDDC‘2020)检测

1. GRDDC2020 数据集介绍 GRDDC2020 数据集是从印度、日本和捷克收集的道路图像。包括三个部分&#xff1a;Train, Test1, Test2。训练集包括带有 PASCAL VOC 格式 XML 文件标注的道路图像。 缺陷类型&#xff1a;D00、D01、D11、D10、D20、D40、D43、D44、D50、D0w0…

Otsu阈值法原理及实现

文章目录 Otsu算法简介Otsu 算法的逻辑源码实现 欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; Otsu算法简介 Otsu阈值法发表于1979年&#xff0c;论文为A threshold selection method from gray level histograms,作者是日本东京大学的…

序列模型基础概念

一、公式定义 在时间 t t t观察到 x t x_{t} xt​&#xff0c;那么得到 T T T个不独立的随机变量 ( x 1 , . . . , x T ) − p ( X ) (x_{1},...,x_{T})-p(X) (x1​,...,xT​)−p(X) 由条件概率公式&#xff1a; p ( a , b ) p ( a ) p ( b ∣ a ) p ( b ) p ( a ∣ b ) p(a,…

chatgpt赋能python:Python中局部变量的介绍

Python中局部变量的介绍 在Python中&#xff0c;局部变量是在函数中定义的变量&#xff0c;其范围限制在该函数内部。每当函数被调用时&#xff0c;局部变量将被创建并且只在函数的执行期间存在。当函数执行结束时&#xff0c;局部变量将被销毁。 局部变量是在函数内部定义的…

代码随想录算法训练营第四十六天 | 力扣 139.单词拆分

139.单词拆分 题目 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 解析 1.确定dp数组以及下标的含义 …

Windows上GIT配置文件的位置

Git作为常见的版本控制系统。在Windows上&#xff0c;我偶尔在CLI上使用官方的版本&#xff1a; Git for Windows 。本文简单介绍Windows下的git配置文件。 系统和全局的gitconfig 配置文件因环境而异&#xff08;Windows 原生的cmd、Windows shell 或 MSYS2 shell&#xff09;…

chatgpt赋能python:Python中如何取消列表

Python中如何取消列表 在Python中使用列表是一种非常常见的数据结构&#xff0c;它允许我们在其中存储任意数量的元素&#xff0c;并且可以非常容易地进行遍历和操作。但是&#xff0c;有时候我们需要从列表中删除元素。这个过程并不难&#xff0c;但是有些细节需要注意。本文…

写最好的Docker安装最新版MySQL8(mysql-8.0.31)教程(参考Docker Hub和MySQL官方文档)

一、前言 MySQL官方安装包下载地址&#xff1a;   https://dev.mysql.com/downloads/mysql/   Docker Hub官方网址&#xff1a;   https://hub.docker.com/ 如果需要了解Centos7下MySQL5.7最新版的安装部署&#xff0c;可参考教程【最新MySQL-5.7.40在云服务器Centos7.…