CCF---201912-3---化学方程式---C++---暴力法

69 篇文章 2 订阅
4 篇文章 0 订阅

问题描述

试题编号:201912-3
试题名称:化学方程式
时间限制:1.0s
内存限制:512.0MB

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

测试数据

(自己手打的,不知道有没有打错,需要的自己检查一下再用)

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

难点及思路

这题的难点在于’(‘和’)'的嵌套问题,可能出现多个嵌套,一般方法都是递归或者用堆栈,这里用了一个“pass”标记,减轻了工作量。我考试的时候用的是递归,然后超时了,最后只有50分。
在这里插入图片描述

实现代码

#include<iostream>
#include<string>
#include<sstream>
#include<map>
#include<vector>

using namespace std;

map<string, int> mp[2];
typedef pair<string, int> Elem; // 定义元素,string 存 id , num 存 个数

// 造数: 注意下标要传引用或者指针,保证下标最终指向非数字
int toNumber(string str, int &pos) {
	int flag = 0;
	while (isdigit(str[pos])) 
		flag = flag * 10 + str[pos++] - '0';
	return flag;
}

void solve(string str, int tag) {
	int coe = 1, pos = 0;		// coe: 系数, pos: 字符串下标
	vector<Elem> arr;			// 存元素的数组
	if (isdigit(str[pos])) coe = toNumber(str, pos); //算出全局系数,也就是最前面的数字

	while (pos < str.size()) {
		if (isdigit(str[pos])) {	// 遇到数字,就开始计算,除了全局系数,其他系数都存在于元素末尾
			int num = toNumber(str, pos);
			int i = arr.size() - 1;
			if (arr[i].first == ")") {	// 数字前一位是')',那么就要一个 '(' , ')' 组合内的所有元素乘倍数
				arr[i].first = "pass";	// 并修改标记,表示已经用过,避免嵌套的括号二次利用
				while (arr[--i].first != "(") arr[i].second *= num; // 找到对应的'('并修改标记
				arr[i].first = "pass";
			}
			else arr[i].second *= num; // 若数字前不是括号,则为元素本身,那么直接乘倍就好了
		}
		else if (str[pos] == '(') { //直接入数组
			arr.push_back(Elem("(", 0));
			pos++;
		}
		else if (str[pos] == ')') {
			arr.push_back(Elem(")", 0));
			if (!isdigit(str[++pos])) str.insert(pos, "1"); // 如果')'后面没有数字,那么我们就给他一个‘1’,保证所有都是')'数字结尾
		}
		else if (isupper(str[pos])) { // 遇到元素
			string name = "";
			name += str[pos];
			pos++;
			if (islower(str[pos])) { //若第二位为小写
				name += str[pos];
				pos++;
			}
			arr.push_back(Elem(name, 1)); //默认初始值都是 1
		}
	}

	for (int i = 0; i != arr.size(); i++) { 
		if (arr[i].first == "pass" ) continue; // 遇到非元素直接pass
		mp[tag][arr[i].first] += arr[i].second * coe;
	}
}

bool Judge(string str) {
	mp[0].clear();
	mp[1].clear();
	int pos = str.find('=');
	string tmp;
	string left = str.substr(0, pos);
	string right = str.substr(pos + 1);
	stringstream left_ss(left), right_ss(right);

	while (getline(left_ss, tmp, '+')) solve(tmp, 0);
	while (getline(right_ss, tmp, '+')) solve(tmp, 1);

	if (mp[0].size() != mp[1].size()) return false;

	for (map<string, int>::iterator it = mp[0].begin(); it != mp[0].end(); it++) 
		if (mp[1][it->first] != it->second) return false;

	return true;
}

int main() {
	int n;
	string str;
	cin >> n;
	while (n--) {
		cin >> str;
		if (Judge(str)) cout << "Y" << endl;
		else cout << "N" << endl;
	}
	return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值