题目描述
标题:表格计算
某次无聊中, 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();
}
}
}