[NA]Lab3:免费午餐-求解周期性三对角阵方程组

任务概述

数值分析课程的第三个实验,CYLL想要计算免费午餐菜单n道菜中每一道菜 di 的真实价格 pi 。每道菜的标价 ci=0.5pi1+2pi+0.5pi+1 。其中, 1in,p1=pn1,pn=p0 .

函数接口定义:

void Price( int n, double p[] );

其中n表示菜的种类数, 2<n10000 。数组p[]存储了每一道菜的标价,将计算得到的真实价格存储在p[]中返回。
裁判程序样例:

#include 

#define Max_size 10000 /* max number of dishes */

void Price( int n, double p[] );

int main()
{
    int n, i;
    double p[Max_size];

    scanf("%d", &n);
    for (i=0; iscanf("%lf", &p[i]);
    Price(n, p);
    for (i=0; iprintf("%.2f ", p[i]);
    printf("\n");

    return 0;
}

/* Your function will be put here */

输入样例:

12 23.64 17.39 12.77 16.62 10.67 14.85 12.68 26.90 28.30 15.59 37.99 23.18

输出样例:

9.20 5.58 3.24 7.00 1.99 6.36 2.25 10.01 11.52 0.50 17.65 4.88

算法思路

根据题意,可以列出如下方程组:

20.5000.50.520.50000.520000020.50.5000.52p0p1p2pn2pn1=c0c1c2cn2cn1

发现系数矩阵并不是一般的三对角阵,这里称为“周期性三对角阵”。注意到左上角n-1维子矩阵为标准三对角阵,因此可以将最后一道菜的实际价格当作待定参数k求解,其中 k=pn1 ,原方程组转化为:
20.50000.520.50000.520000020.50000.52p0p1p2pn3pn2=c00.5kc1c2cn3cn20.5k

使用Crout分解算法得到前n-1项含参数k的表达,再通过 cn1=0.5pn2+2pn1+0.5p0 求k,即可得到最终结果。

[NA]Lab3:免费午餐-求解周期性三对角阵方程组_第1张图片

实现细节

由于引入了一个参数k,导致我们不能用常规的方法直接对Lz=b和Ux=z进行求解。观察到算法具有严格的递推性,带有参数k的方程组求解可以按如下方法求解:
1.首先求解Lz=b,这里L代表分解产生的下三角阵,b代表列向量(也就是增广矩阵的最后一列,书中算法的 ai,n+1 列)。由于列向量含参数k,因此对于每一项 zi ,我们只能将其表示为k的线性函数(形如 zi=ai+bik )。这样我们就逐项得到了z关于k的函数表达。
2.对于Ux=z的求解同理。算法的Step5写出了x与z的递推关系,我们也可以按照上述思路将x也表达为k的线性函数(形如 xi=(ai+bik)ui,i+1xi+1=(si+tik) )。这样我们也逐项得到了x关于k的函数表达。
3.求解k,我们使用 cn1=0.5pn2+2pn1+0.5p0 整理得到k的算术表达式即可。
4.最后写一个循环将x的每一项由k算出,完成全部求解。

心得体会

[NA]Lab3:免费午餐-求解周期性三对角阵方程组_第2张图片
这次实验作业好像是本人学习编程以来,第一次在PTA系统上一条通过,值得纪念。算法虽然简单,但很好的练习并理解了特殊矩阵的线性推倒过程。注意到题目要求的维度最大是10000,如果使用其他方法(例如直接使用高斯消元法),我们需要直接申请10000*10000的浮点型数组,不仅内存开销很大,同时误差积累也十分明显,很可能无法得到正确的结果。因此对于矩阵的求解,应该具体问题具体分析。

你可能感兴趣的:(数值分析)