1103. Integer Factorization (30)--dfs

本文介绍了一个求解特定幂次和等于给定数值N的问题的算法实现。通过递归深度优先搜索的方法寻找组成N的所有K个数的P次幂之和,并确保找到的解中各数递增且唯一。该算法还包含了多项优化措施,如预先计算幂次表、剪枝等。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>

#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <stack>

using namespace std;

int N,K,P;
vector<int> v,ans;
int maxx=-1;

int po[400]={0};//直接打表,免得每次用到都得pow(),另外,pow()算int有误差!!最好自己写一个

int power(int d,int p)
{
    if(p==0)
        return 1;

    int ans=1;
    for(int i=0;i<p;i++)
    {
        ans*=d;
    }
    return ans;
}

int m=1;
void init()
{
    while(power(m,P)<=N)
    {
        po[m]=power(m,P);
        m++;//最后会多一个
    }
}

void dfs(int cou,int sum,int disum)
{
    if(sum>N)//剪枝2
        return;

    if(cou==K)
    {
        if(sum==N&&disum>=maxx)
        {
            ans=v;
            maxx=disum;
        }

        return;
    }

    int lower=(cou==0?1:v[cou-1]);//剪枝1:为避免重复,保持递增
    for(int i=lower;i<=m;i++)
    {
        v.push_back(i);
        if(sum+po[i]>N)
        {
            v.pop_back();
            break;
        }
        dfs(cou+1,sum+po[i],disum+i);
        v.pop_back();
    }

    return;
}
bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    freopen("in.txt","r",stdin);

    scanf("%d %d %d",&N,&K,&P);
    init();
    m--;//减去上面m++误加的一个
    dfs(0,0,0);

    sort(ans.begin(),ans.end(),cmp);
    if(maxx==-1)
    {
        printf("Impossible");
        return 0;
    }

    printf("%d = ",N);
    for(int i=0;i<ans.size();i++)
    {
        printf("%d^%d",ans[i],P);
        if(i!=ans.size()-1)
        {
            printf(" + ");
        }
    }

    return 0;
}





# 题目重述 给定线性方程组 $ A\mathbf{x} = \mathbf{b} $,其中: $$ A = \begin{bmatrix} 1 & 2 & 6 \\ 7 & 4 & 8 \\ -1 & 5 & 5 \\ \end{bmatrix}, \quad \mathbf{b} = \begin{bmatrix} 10 \\ -2 \\ 3 \\ \end{bmatrix} $$ 要求使用**间接 LU 解法**(即先对 $ A $ 进行 LU 解,再通过前向和后向替换求解)求解未知向量 $ \mathbf{x} = [x_1, x_2, x_3]^T $。用 C 语言实现。 --- # 详解 ### 步骤一:LU 解(Doolittle 方法) 将矩阵 $ A $ 解为单位下三角矩阵 $ L $ 和上三角矩阵 $ U $,使得: $$ A = LU $$ 采用 Doolittle 解($ L $ 对角线为 1): 设: $$ L = \begin{bmatrix} 1 & 0 & 0 \\ l_{21} & 1 & 0 \\ l_{31} & l_{32} & 1 \\ \end{bmatrix}, \quad U = \begin{bmatrix} u_{11} & u_{12} & u_{13} \\ 0 & u_{22} & u_{23} \\ 0 & 0 & u_{33} \\ \end{bmatrix} $$ 逐元素计算: #### 第1行(U)与第1列(L): - $ u_{11} = a_{11} = 1 $ - $ u_{12} = a_{12} = 2 $ - $ u_{13} = a_{13} = 6 $ - $ l_{21} = a_{21}/u_{11} = 7/1 = 7 $ - $ l_{31} = a_{31}/u_{11} = -1/1 = -1 $ #### 第2行(U)与第2列(L): - $ u_{22} = a_{22} - l_{21}u_{12} = 4 - 7×2 = 4 - 14 = -10 $ - $ u_{23} = a_{23} - l_{21}u_{13} = 8 - 7×6 = 8 - 42 = -34 $ - $ l_{32} = (a_{32} - l_{31}u_{12}) / u_{22} = (5 - (-1)(2)) / (-10) = (5+2)/(-10) = -0.7 $ #### 第3行(U): - $ u_{33} = a_{33} - l_{31}u_{13} - l_{32}u_{23} $ $$ = 5 - (-1)(6) - (-0.7)(-34) = 5 + 6 - 23.8 = -12.8 $$ 所以得到: $$ L = \begin{bmatrix} 1 & 0 & 0 \\ 7 & 1 & 0 \\ -1 & -0.7 & 1 \\ \end{bmatrix}, \quad U = \begin{bmatrix} 1 & 2 & 6 \\ 0 & -10 & -34 \\ 0 & 0 & -12.8 \\ \end{bmatrix} $$ --- ### 步骤二:解 $ L\mathbf{y} = \mathbf{b} $ (前向替换) 令 $ \mathbf{y} = [y_1, y_2, y_3]^T $ 1. $ y_1 = b_1 = 10 $ 2. $ y_2 = b_2 - l_{21}y_1 = -2 - 7×10 = -72 $ 3. $ y_3 = b_3 - l_{31}y_1 - l_{32}y_2 = 3 - (-1)(10) - (-0.7)(-72) = 3 + 10 - 50.4 = -37.4 $ 得:$ \mathbf{y} = [10,\ -72,\ -37.4]^T $ --- ### 步骤三:解 $ U\mathbf{x} = \mathbf{y} $ (后向替换) 1. $ x_3 = y_3 / u_{33} = -37.4 / (-12.8) \approx 2.921875 $ 2. $ x_2 = (y_2 - u_{23}x_3)/u_{22} = (-72 - (-34)(2.921875)) / (-10) $ $$ = (-72 + 99.34375)/(-10) = 27.34375 / (-10) = -2.734375 $$ 3. $ x_1 = (y_1 - u_{12}x_2 - u_{13}x_3)/u_{11} $ $$ = 10 - 2(-2.734375) - 6(2.921875) = 10 + 5.46875 - 17.53125 = -2.0625 $$ 最终解: $$ \mathbf{x} = \begin{bmatrix} -2.0625 \\ -2.734375 \\ 2.921875 \\ \end{bmatrix} $$ --- ### ✅ C语言代码实现(LU解 + 前向/后向替换) ```c #include <stdio.h> #define N 3 // 打印向量 void print_vector(double v[N], const char* name) { printf("%s = [\n", name); for (int i = 0; i < N; i++) { printf(" %.6f\n", v[i]); } printf("]\n"); } // LU解(Doolittle) void lu_decomposition(double A[N][N], double L[N][N], double U[N][N]) { int i, j, k; // 初始化 for (i = 0; i < N; i++) for (j = 0; j < N; j++) L[i][j] = U[i][j] = 0.0; for (i = 0; i < N; i++) { // U: 第i行 for (j = i; j < N; j++) { U[i][j] = A[i][j]; for (k = 0; k < i; k++) U[i][j] -= L[i][k] * U[k][j]; } // L: 第i列 L[i][i] = 1.0; // 单位下三角 for (j = i + 1; j < N; j++) { L[j][i] = A[j][i]; for (k = 0; k < i; k++) L[j][i] -= L[j][k] * U[k][i]; L[j][i] /= U[i][i]; } } } // 前向替换 Ly = b void forward_substitution(double L[N][N], double b[N], double y[N]) { for (int i = 0; i < N; i++) { y[i] = b[i]; for (int j = 0; j < i; j++) y[i] -= L[i][j] * y[j]; } } // 后向替换 Ux = y void backward_substitution(double U[N][N], double y[N], double x[N]) { for (int i = N-1; i >= 0; i--) { x[i] = y[i]; for (int j = i+1; j < N; j++) x[i] -= U[i][j] * x[j]; x[i] /= U[i][i]; } } int main() { // 系数矩阵 A double A[N][N] = { {1, 2, 6}, {7, 4, 8}, {-1, 5, 5} }; // 右端向量 b double b[N] = {10, -2, 3}; // LU解结果 double L[N][N], U[N][N]; double y[N], x[N]; // 中间向量和解向量 // 执行LU解 lu_decomposition(A, L, U); // 解 Ly = b forward_substitution(L, b, y); // 解 Ux = y backward_substitution(U, y, x); // 输出结果 printf("=== LU 解结果 ===\n"); printf("\nL 矩阵:\n"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) printf("%8.4f ", L[i][j]); printf("\n"); } printf("\nU 矩阵:\n"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) printf("%8.4f ", U[i][j]); printf("\n"); } print_vector(x, "解向量 x"); return 0; } ``` --- ### 输出示例: ``` L 矩阵: 1.0000 0.0000 0.0000 7.0000 1.0000 0.0000 -1.0000 -0.7000 1.0000 U 矩阵: 1.0000 2.0000 6.0000 0.0000 -10.0000 -34.0000 0.0000 0.0000 -12.8000 解向量 x = [ -2.062500 -2.734375 2.921875 ] ``` 与手工计算一致! --- # 知识点 - **LU解(Doolittle)**:将矩阵解为下三角 $ L $ 和上三角 $ U $,便于多次求解 - **前向与后向替换**:解 $ L\mathbf{y}=\mathbf{b} $ 和 $ U\mathbf{x}=\mathbf{y} $ 实现高效求解 - **数值稳定性注意**:当主元过小时应考虑部选主元避免误差放大
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值