第六届蓝桥杯决赛 B组第5题表格计算

题目描述
标题:表格计算
某次无聊中, atm 发现了一个很老的程序。这个程序的功能类似于 Excel ,它对一个表格进行操作。
不妨设表格有 n 行,每行有 m 个格子。
每个格子的内容可以是一个正整数,也可以是一个公式。
公式包括三种:
1. SUM(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的和。
2. AVG(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的平均数。
3. STD(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的标准差。

标准差即为方差的平方根。
方差就是:每个数据与平均值的差的平方的平均值,用来衡量单个数据离开平均数的程度。

公式都不会出现嵌套。

如果这个格子内是一个数,则这个格子的值等于这个数,否则这个格子的值等于格子公式求值结果。

输入这个表格后,程序会输出每个格子的值。atm 觉得这个程序很好玩,他也想实现一下这个程序。

「输入格式」
第一行两个数 n, m 。
接下来 n 行输入一个表格。每行 m 个由空格隔开的字符串,分别表示对应格子的内容。
输入保证不会出现循环依赖的情况,即不会出现两个格子 a 和 b 使得 a 的值依赖 b 的值且 b 的值依赖 a 的值。

「输出格式」
输出一个表格,共 n 行,每行 m 个保留两位小数的实数。
数据保证不会有格子的值超过 1e6 。

「样例输入」
3 2
1 SUM(2,1:3,1)
2 AVG(1,1:1,2)
SUM(1,1:2,1) STD(1,1:2,2)

「样例输出」
1.00 5.00
2.00 3.00
3.00 1.48

「数据范围」
对于 30% 的数据,满足: n, m <= 5
对于 100% 的数据,满足: n, m <= 50

资源约定:
峰值内存消耗(含虚拟机) < 512M
CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

解题思路
本题最大的难点就是表格计算中各个单元格的计算顺序未知,某些带有函数的单元格计算是有前置条件的,因此我采用的方案是:
使用一个判断矩阵,用于记录表格矩阵中对应表格的值是否已经计算出了,一个计算表格矩阵总记录数的变量rue判断是否计算完成
使用一个递归函数对表格矩阵进行计算,若判断矩阵中对应位置未计算,则计算。如果该单元格能计算出值则rue+1,再递归到下一个单元格进行计算;如果该单元格不能计算出值,则直接跳过计算下一个单元格值,循环递归计算,直到rue=n*m时,计算完成,退出计算。
java代码

import java.util.Scanner;

public class Main5 {
    static String M[][]=new String[51][51];//表格矩阵 - 用于存放表格数据
    static boolean R[][]=new boolean[51][51];//判断矩阵 - 用于判断表格矩阵对应位置的值是否已计算
    static int n,m;//表格矩阵的行,列

    public static double SUM(String X1,String Y1,String X2,String Y2){
        double re=0;
        int x1=Integer.parseInt(X1),x2=Integer.parseInt(X2),y1=Integer.parseInt(Y1),y2=Integer.parseInt(Y2);
        for(int i=x1;i<=x2;i++)
            for(int j=y1;j<=y2;j++)
                re+=Double.parseDouble((M[i][j]));  
        return re;
    }

    public static double AVG(String X1,String Y1,String X2,String Y2){
        return SUM(X1,Y1,X2,Y2)/((Integer.parseInt(Y2)+1-Integer.parseInt(Y1))*(Integer.parseInt(X2)+1-Integer.parseInt(X1)));
    }

    public static double STD(String X1,String Y1,String X2,String Y2){
        double re=0,x=AVG(X1,Y1,X2,Y2);
        int x1=Integer.parseInt(X1),x2=Integer.parseInt(X2),y1=Integer.parseInt(Y1),y2=Integer.parseInt(Y2);
        for(int i=x1;i<=x2;i++)
            for(int j=y1;j<=y2;j++)
                re+=Math.pow((Double.parseDouble(M[i][j])-x), 2);
        return Math.sqrt(re/((y2+1-y1)*(x2+1-x1)));
    }   

    public static void mutil(int rue,int x,int y)//递归计算表格矩阵各个单元格的值
    {
        if(rue==(n*m))//若已计算表格矩阵所有单元格的值,结束递归计算
            return;
        if(!R[x][y])//若表格矩阵的该位置单元格还未计算
        {
            String temp[]=M[x][y].split("\\(|,|:|\\)");//分割单元格内语句
            if(temp[0].equals("SUM"))//若为求和函数
            {
                try{
                    M[x][y]=SUM(temp[1],temp[2],temp[3],temp[4])+"";//调用求和函数
                    ex1(rue,x,y);
                }catch(Exception e){ex2(rue,x,y);}
            }
            else if(temp[0].equals("AVG"))//若为求平均值函数
            {
                try{
                    M[x][y]=AVG(temp[1],temp[2],temp[3],temp[4])+"";//调用求平均值函数
                    ex1(rue,x,y);
                }catch(Exception e){ex2(rue,x,y);}
            }
            else if(temp[0].equals("STD"))//若为求标准差函数
            {
                try{
                    M[x][y]=STD(temp[1],temp[2],temp[3],temp[4])+"";//调用求标准差函数
                    ex1(rue,x,y);
                }catch(Exception e){ex2(rue,x,y);}
            }
            else//若为单独的数值
                ex1(rue,x,y);
        }//end if(!R[x][y])
        else
            ex2(rue,x,y);
    }

    public static void ex1(int rue,int x,int y)//能计算正确情况下(即x1,y1:x2,y2对应矩阵已全部转为数值,没有函数),递归调用mutil函数计算一下个单元格的值,并将已计算单元格数+1
    {
        R[x][y]=true;
        if(x==n&&y==m)
            mutil(rue+1,1,1);
        else if(y==m)
            mutil(rue+1,x+1,1);
        else
            mutil(rue+1,x,y+1);
    }

    public static void ex2(int rue,int x,int y)//无法计算情况下(即x1,y1:x2,y2对应矩阵中还存在函数未计算),递归调用mutil函数计算一下个单元格的值,已计算单元格数不变
    {
        if(x==n&&y==m)
            mutil(rue,1,1);
        else if(y==m)
            mutil(rue,x+1,1);
        else
            mutil(rue,x,y+1);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        n=scan.nextInt();m=scan.nextInt();//输入行,列
        for(int i=1;i<=n;i++)//输入表格矩阵
            for(int j=1;j<=m;j++)
                M[i][j]=scan.next();

        for(int i=1;i<=n;i++)//初始化判断矩阵
            for(int j=1;j<=m;j++)
                R[i][j]=false;

        mutil(0,1,1);//递归计算
        for(int i=1;i<=n;i++)//输出结果
        {
            for(int j=1;j<=m;j++)
                System.out.printf("%.2f ",Double.parseDouble(M[i][j]));
            System.out.println();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32352777/article/details/80239725