标题:表格计算

某次无聊中, 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,否则按无效代码处理。

这里唯一有点弯路的是

1.表中的每一个公式是否可以处理

2.处理多少次后表中公式全部处理完成

没有想到好的办法,因此用了while

测试网址:https://www.dotcpp.com/oj/problem1832.html

import java.util.Scanner;
public class Main {
	Table[][] set;//存放表
	class Table{
		float value;//存放每个表格值
		boolean isvalue=false;//标记该表格是一个值true还是一个公式false
		String str="";//存放一个公式
		public Table(float v,boolean iv,String s) {
			this.value=v;
			this.isvalue=iv;
			this.str=s;
		}
	}
	public Main() {
		Scanner sn=new Scanner(System.in);
		int n=sn.nextInt();
		int m=sn.nextInt();
		set=new Table[n][m];
		/*
		 * 1..读取每个数据,判断是值还是公式
		 * 2..分开存放
		 * */
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				String string=sn.next().trim();
				if(string.charAt(0)<58) {
					set[i][j]=new Table(Float.parseFloat(string), true,"");
				}else {
					set[i][j]=new Table(0, false,string);
				}
			}
		}
		//判断表中是否含有公式,有公式就进行遍历处理,没有则跳过
		while(!isAllValues()) {
			for(int i=0;i<n;i++) {
				for(int j=0;j<m;j++) {
				    deal(set[i][j]);
				}
			}
		}
		//输出数据
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				System.out.print(String.format("%.2f", set[i][j].value));
				System.out.print("\t");
			}
			System.out.println();
		}
	}
	//处理表格数据
	public void deal(Table table) {
		//表格里为公式的话则进行处理
		if(!table.isvalue) {
			//这里本人暂时不会用正则表达式
			//因此耗费一大段进行字符串拆分得到x1,x2,y1,y2
			String str=table.str;
			str=str.substring(4);
		    int x1=Integer.parseInt(str.substring(0, str.indexOf(",")));
			int y1=Integer.parseInt(str.substring(str.indexOf(",")+1, str.indexOf(":")));
			str=str.substring(str.indexOf(":")+1);
			int x2=Integer.parseInt(str.substring(0, str.indexOf(",")));
			int y2=Integer.parseInt(str.substring(str.indexOf(",")+1, str.indexOf(")")));
			//根据公式开头区分处理
			if(table.str.startsWith("SUM")) {
				float sum=0;
				for(int i=x1-1;i<x2;i++) {
					for(int j=y1-1;j<y2;j++) {
						if(set[i][j].isvalue) {
							sum+=set[i][j].value;
						}else {
							return;
						}
					}
				}
				table.value=sum;
			}else if(table.str.startsWith("AVG")) {
				float sum=0;
				for(int i=x1-1;i<x2;i++) {
					for(int j=y1-1;j<y2;j++) {
						if(set[i][j].isvalue) {
							sum+=set[i][j].value;
						}else {
							return;
						}
					}
				}
				table.value=sum/((x2-x1+1)*(y2-y1+1));
			}else if(table.str.startsWith("STD")) {
				float sum=0;
				for(int i=x1-1;i<x2;i++) {
					for(int j=y1-1;j<y2;j++) {
						if(set[i][j].isvalue) {
							sum+=set[i][j].value;
						}else {
							return;
						}
					}
				}
				float avg=sum/((x2-x1+1)*(y2-y1+1));
				float s=0;
				for(int i=x1-1;i<x2;i++) {
					for(int j=y1-1;j<y2;j++) {
						s=s+(set[i][j].value-avg)*(set[i][j].value-avg);
					}
				}
				table.value=(float) Math.sqrt(s/((x2-x1+1)*(y2-y1+1)));
			}
			//处理完成修改表格的标记
			table.isvalue=true;
		}
	}
	//遍历查找是否还有公式
	public boolean isAllValues() {
		for(int i=0;i<set.length;i++) {
			for(int j=0;j<set[i].length;j++) {
				if(!set[i][j].isvalue)return false;
			}
		}
		return true;
	};

	public static void main(String[] args) {
		new Main();
	}
	

}