ccf-csp 1912-3 化学方程式(Java)


官网传送门
参考文献

题目描述

题目描述
格式要求
子任务

输入案例

官网给的都是图片,本人已手敲好,未免节约大家时间,故共享供复制粘贴。
11
H2+O2=H2O
2H2+O2=2H2O
H2+Cl2=2NaCl
H2+Cl2=2HCl
CH4+2O2=CO2+2H2O
CaCl2+2AgNO3=Ca(NO3)2+2AgCl
3Ba(OH)2+2H3PO4=6H2O+Ba3(PO4)2
3Ba(OH)2+2H3PO4=Ba3(PO4)2+6H2O
4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
4Au+8NaCN+2H2O+O2=4Na(Au(CN)2)+4NaOH
Cu+As=Cs+Au

解题思路

巴科斯范式,递归定义,所以肯定要用递归的思想解题。下面采用自顶向下的方法介绍解题思路。
  • 分别处理等号两边的<expr>,得到各自的原子类别及相应的数目。若两边相同,返回true;否则,返回false;

  • <expr>拆分为多个<coef><formula>,解析<coef>。解析<formula>,所得的<atom : nums>中nums需乘以coef

  • 解析<formula>
    注意:此时 s 只可能以大小字母或 ‘(’ 开头

    1. ‘(’ 开头
      a. 寻找与之匹配的’)’
      b. 计算 ‘)’ 后面的系数 coef
      c. 递归 : 将括号里的内容和 time * coef 传给 analyzeFormula
    2. 大写字母开头
      a. 判断 s 第二位是否是小写字母,得到原子名
      b. 计算原子后面的系数 coef
      c. 将原子和其数目 time * coef 推进 map
      d. 递归 : 将系数后面的内容和 time 传给 analyzeFormula

AC代码

import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.HashMap;
import java.util.Set;

public class Main {
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		in.nextLine();
		while (n-- > 0) {
			if (isEqualFormula(in.nextLine())) {
				System.out.println("Y");
			} else {
				System.out.println("N");
			}
		}
		in.close();
	}

	public static Boolean isEqualFormula(String s) {
		// 获取等号两边表达式
		String[] expression = s.split("=");
		String left_expression = expression[0];
		String right_expression = expression[1];
		// 解析等号两边表达式,获得其原子组成及相应原子数目
		Map<String, Integer> left_atom = analyzeExpression(left_expression);
		Map<String, Integer> right_atom = analyzeExpression(right_expression);
		// 判断方程式是否配平
		if (left_atom.equals(right_atom)) {
			return true;
		} else {
			return false;
		}
	}

	// 解析表达式
	public static Map<String, Integer> analyzeExpression(String s) {
		// 存储整个表达式的原子组成
		Map<String, Integer> map = new HashMap<>();
		// 存储某个 <coef><formula> 的原子组成
		Map<String, Integer> cur = new HashMap<>();
		
		// 顺序处理每一个 <coef><formula>
		String[] exprs =s.split("\\+");
		for(String expr : exprs) {
			int loc = 0; // 标记第一个非 0 元素的位置
			while(loc < expr.length() && expr.charAt(loc) >= '0' && expr.charAt(loc) <= '9') loc++;
			// loc 等于 0 说明 <coef> 为 1,否则解析
			int coef = loc == 0 ? 1 : Integer.parseInt(expr.substring(0, loc));
			// 对 <formula> 进行解析,将 coef 作为倍数传进去,返回map
			cur = analyzeFormula(expr.substring(loc), coef);
			// 依次将 cur 中的内容补充到 map 中
			Set<Entry<String, Integer>> set = cur.entrySet();
			for(Entry<String, Integer> item : set) {
				String key = item.getKey();
				int val = item.getValue();
				if(map.containsKey(key)) {
					map.put(key, map.get(key) + val);
				}
				else map.put(key, val);
			}
		}
		return map;
	}
	
	public static Map<String, Integer> analyzeFormula(String s, int time) {
		/*
		注意:此时 s 只可能以大小字母或 '(' 开头
		1. '(' 开头
			a. 寻找与之匹配的')'
			b. 计算 ')' 后面的系数 coef
			c. 递归 : 将括号里的内容和 time * coef 传给 analyzeFormula
		2. 大写字母开头
			a. 判断 s 第二位是否是小写字母,得到原子名
			b. 计算原子后面的系数 coef
			c. 将原子和其数目  time * coef 推进 map 中
			d. 递归 : 将系数后面的内容和 time 传给 analyzeFormula
		*/
		Map<String, Integer> map = new HashMap<>();
		if(s.isEmpty()) return map;
		
		// 以括号开头,去括号,计算系数,递归
		if(s.charAt(0) == '(') {
			int banlance = 1; // 左括号数 - 右括号数
			int loc = 1;	  // 与该 '(' 对应的 ')' 的后一个位置
			while(banlance > 0) {
				if(s.charAt(loc) == '(') banlance++;
				else if(s.charAt(loc) == ')') banlance--;
				loc++;
			}
			// right 记录 ')' 的后一个位置,loc 继续寻找系数 coef 的后一个位置
			int right = loc; 
			while(loc < s.length() && s.charAt(loc) >= '0' && s.charAt(loc) <= '9') {
				loc++;
			}
			int coef = loc == right ? 1 : Integer.parseInt(s.substring(right, loc));
			
			Map<String, Integer> cur = new HashMap<>();
			Set<Entry<String, Integer>> set;
			// 递归括号里面的东西
			cur = analyzeFormula(s.substring(1, right - 1), time * coef);
			set = cur.entrySet();
			for(Entry<String, Integer> item : set) {
				String key = item.getKey();
				int val = item.getValue();
				if(map.containsKey(key)) {
					map.put(key, map.get(key) + val);
				}
				else map.put(key, val);
			}
			// 递归括号系数后面的东西
			cur = analyzeFormula(s.substring(loc), time);
			set = cur.entrySet();
			for(Entry<String, Integer> item : set) {
				String key = item.getKey();
				int val = item.getValue();
				if(map.containsKey(key)) {
					map.put(key, map.get(key) + val);
				}
				else map.put(key, val);
			}
		}
		// 此时只可能以大写字母开头
		else {
			String key;
			int loc = 1; // 标记系数此时的地方
			if(s.length() > 1 && s.charAt(1) >= 'a' && s.charAt(1) <= 'z') {
				key = s.substring(0, 2);
				loc = 2;
			}
			else key = s.substring(0, 1);
			// right 记录原子的后一个位置也即系数起始的位置,loc 继续寻找系数 coef 的后一个位置
			int right = loc;
			while(loc < s.length() && s.charAt(loc) >= '0' && s.charAt(loc) <= '9') loc++;
			int coef = loc == right ? 1 : Integer.parseInt(s.substring(right, loc));
			if(map.containsKey(key)) {
				map.put(key, map.get(key) + coef * time);
			}
			else map.put(key, coef * time);
			
			Map<String, Integer> cur = new HashMap<>();
			Set<Entry<String, Integer>> set;
			// 递归该原子及其系数后面的东西
			cur = analyzeFormula(s.substring(loc), time);
			set = cur.entrySet();
			for(Entry<String, Integer> item : set) {
				key = item.getKey();
				int val = item.getValue();
				if(map.containsKey(key)) {
					map.put(key, map.get(key) + val);
				}
				else map.put(key, val);
			}
		}
		return map;
	}
}

注意事项

太多需要注意的地方了,就不说了…

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值