csp-化學方程式

化學方程式

這是一個化學方程式檢測的算法題,只是檢測物料守恆,題目不是特別難,但是字符串處理時還是挺繁瑣的,假期一直宅在家裏,好久沒更新博客了。算是記錄一下解題的思路把。
wyt
wyt
wyt

wyt
下面是完整代碼

#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
using namespace std;

struct element {
	string s;
	int amount;
	element() :s(""), amount(0) {};
	element(string st) :s(st), amount(0) {};
	element(string st, int a) :s(st), amount(a) {};
	bool operator < (const element& e) {
		return s < e.s;
	}
	bool operator == (const element& e) {
		return s == e.s;
	}
};


class elements {
public:
	vector<element> es;
	elements() {};
	elements(element e) {
		es.push_back(e);
	}
	void add_element(string ele_name, int amount) {
		element t_e = element(ele_name, amount);
		auto i = find(es.begin(), es.end(), t_e);
		if (i == es.end()) {
			es.push_back(t_e);
		}
		else {
			i->amount += amount;
		}
	}

	void show() {
		for (auto t : es) {
			cout << t.s << '\t' << t.amount << endl;
		}
		cout << endl << endl;
	}

	void up_elements(elements& e_t, int mul_num) {
		for (auto i : e_t.es) {
			auto j = find(es.begin(), es.end(), i);
			if (j == es.end()) {
				i.amount *= mul_num;
				es.push_back(i);
			}
			else {
				j->amount += i.amount * mul_num;
			}
		}
	}

	bool operator == (const elements& es_t) {
		if (es_t.es.size() != es.size()) {
			return false;
		}
		for (int i = 0; i < es.size(); i++) {
			if (es[i].s != es_t.es[i].s || es[i].amount != es_t.es[i].amount) {
				return false;
			}
		}
		return true;
	}

	bool is_equal(elements& es_t) {
		sort(es.begin(), es.end());
		sort(es_t.es.begin(), es_t.es.end());
		if (*this == es_t) {
			return true;
		}
		return false;
	}
};

elements r_left, r_right;
vector<string> l_s, r_s;
char result[100];
stringstream ss;

void split_s(string s) {
	ss.clear();
	ss.str(s);
	string tmp[2];
	int i_t = 0;
	string tmp_s;
	while (getline(ss, tmp[i_t++], '='));
	ss.clear();
	ss.str(tmp[0]);
	while (getline(ss, tmp_s, '+')) {
		l_s.push_back(tmp_s);
	}
	ss.clear();
	ss.str(tmp[1]);
	while (getline(ss, tmp_s, '+')) {
		r_s.push_back(tmp_s);
	}
}

elements cal(string s) {
	elements r_tmp;
	int prefix_num;
	string prefix_str;

	string e_s_t;

	int j_tmp = 0;

	while (s[j_tmp] >= '0' && s[j_tmp] <= '9') {
		prefix_str += s[j_tmp];
		j_tmp++;
	}
	prefix_num = prefix_str.size() ? stoi(prefix_str) : 1;

	while (1) {
		if (j_tmp < s.size()) {
			if (s[j_tmp] >= 'A' && s[j_tmp] <= 'Z') {
				if (e_s_t.size()) {
					r_tmp.add_element(e_s_t, prefix_num);
					e_s_t.clear();
				}
				e_s_t += s[j_tmp];
				j_tmp++;
			}
			else if (s[j_tmp] >= 'a' && s[j_tmp] <= 'z') {
				e_s_t += s[j_tmp];
				j_tmp++;
			}
			else if (s[j_tmp] >= '0' && s[j_tmp] <= '9') {
				string inner_str;
				int inner_num;
				while (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
					inner_str += s[j_tmp];
					j_tmp++;
				}
				inner_num = inner_str.size() ? stoi(inner_str) : 1;
				r_tmp.add_element(e_s_t, inner_num * prefix_num);
				e_s_t.clear();
			}
			else if (s[j_tmp] == '(') {
				if (e_s_t.size()) {
					r_tmp.add_element(e_s_t, prefix_num);
					e_s_t.clear();
				}
				int pos1 = j_tmp + 1;
				int flag = 0;
				while (1) {
					if (s[j_tmp] == '(') {
						flag++;
					}
					if (s[j_tmp] == ')') {
						flag--;
					}
					if (flag == 0) {
						j_tmp++;
						break;
					}
					j_tmp++;
				};
				int pos2 = j_tmp - 1;
				int size_tmp = pos2 - pos1;
				string deep_string = s.substr(pos1, size_tmp);
				elements r_tmp_e = cal(deep_string);

				string inner_str;
				int inner_num;
				if (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
					while (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
						inner_str += s[j_tmp];
						j_tmp++;
					}
				}
				inner_num = inner_str.size() ? stoi(inner_str) : 1;
				r_tmp.up_elements(r_tmp_e, inner_num* prefix_num);
			}
		}
		else {
			if (e_s_t.size()) {
				r_tmp.add_element(e_s_t, prefix_num);
				e_s_t.clear();
			}
			break;
		}
	}
	return r_tmp;
}

void calc() {
	elements e_tmp;
	for (auto& i : l_s) {
		e_tmp = cal(i);
		r_left.up_elements(e_tmp, 1);
	}
	for (auto& i : r_s) {
		e_tmp = cal(i);
		r_right.up_elements(e_tmp, 1);
	}
	l_s.clear();
	r_s.clear();
}


void sol() {
	int n;
	cin >> n;
	string tmp_s;
	for (int i = 0; i < n; i++) {
		cin >> tmp_s;
		split_s(tmp_s);
		calc();
		if (r_left.is_equal(r_right)) {
			result[i] = 'Y';
		}
		else {
			result[i] = 'N';
		}
		//r_left.show();
		//r_right.show();
		r_left.es.clear();
		r_right.es.clear();
	}
	int pos = 0;
	while (result[pos] == 'N' || result[pos] == 'Y') {
		cout << result[pos]<<endl;
		pos++;
	}
}

int main() {
	sol();
	return 0;
}

這裏的核心算法其實就是cal函數,這個函數主要是拆分字符串爲基本元素符號,並統計個數,比如說將"2H2O拆分成兩個struct,e1=element(‘H’,4),e2=element(‘O’,2)",下面分析一下這個函數.

struct element {
	string s;
	int amount;
	element() :s(""), amount(0) {};
	element(string st) :s(st), amount(0) {};
	element(string st, int a) :s(st), amount(a) {};
	bool operator < (const element& e) {
		return s < e.s;
	}
	bool operator == (const element& e) {
		return s == e.s;
	}
};


class elements {
public:
	vector<element> es;
};
elements cal(string s) {
	elements r_tmp;
	int prefix_num;
	string prefix_str;

	string e_s_t;

	int j_tmp = 0;

	while (s[j_tmp] >= '0' && s[j_tmp] <= '9') {
		prefix_str += s[j_tmp];
		j_tmp++;
	}
	prefix_num = prefix_str.size() ? stoi(prefix_str) : 1;

	while (1) {
		if (j_tmp < s.size()) {
			if (s[j_tmp] >= 'A' && s[j_tmp] <= 'Z') {
				if (e_s_t.size()) {
					r_tmp.add_element(e_s_t, prefix_num);
					e_s_t.clear();
				}
				e_s_t += s[j_tmp];
				j_tmp++;
			}
			else if (s[j_tmp] >= 'a' && s[j_tmp] <= 'z') {
				e_s_t += s[j_tmp];
				j_tmp++;
			}
			else if (s[j_tmp] >= '0' && s[j_tmp] <= '9') {
				string inner_str;
				int inner_num;
				while (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
					inner_str += s[j_tmp];
					j_tmp++;
				}
				inner_num = inner_str.size() ? stoi(inner_str) : 1;
				r_tmp.add_element(e_s_t, inner_num * prefix_num);
				e_s_t.clear();
			}
			else if (s[j_tmp] == '(') {
				if (e_s_t.size()) {
					r_tmp.add_element(e_s_t, prefix_num);
					e_s_t.clear();
				}
				int pos1 = j_tmp + 1;
				int flag = 0;
				while (1) {
					if (s[j_tmp] == '(') {
						flag++;
					}
					if (s[j_tmp] == ')') {
						flag--;
					}
					if (flag == 0) {
						j_tmp++;
						break;
					}
					j_tmp++;
				};
				int pos2 = j_tmp - 1;
				int size_tmp = pos2 - pos1;
				string deep_string = s.substr(pos1, size_tmp);
				elements r_tmp_e = cal(deep_string);

				string inner_str;
				int inner_num;
				if (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
					while (j_tmp < s.size() && s[j_tmp] >= '0' && s[j_tmp] <= '9') {
						inner_str += s[j_tmp];
						j_tmp++;
					}
				}
				inner_num = inner_str.size() ? stoi(inner_str) : 1;
				r_tmp.up_elements(r_tmp_e, inner_num* prefix_num);
			}
		}
		else {
			if (e_s_t.size()) {
				r_tmp.add_element(e_s_t, prefix_num);
				e_s_t.clear();
			}
			break;
		}
	}
	return r_tmp;
}

上面的代碼沒怎麼寫註釋,習慣了,儘管知道不太好,但是一直沒改。
下面說一下字符串分解函數

  • 計算前綴數字,也就是化學物質的摩爾數
  • 遍歷元素,會遇到5種情況
  • 1)大寫字母,這時如果前面不是數字,則需要存儲前面的element,數量爲前綴長度,然後遍歷下一個
  • 2)小寫字母,這時遍歷下一個字符
  • 3)數字,這裏有一個注意點,需要注意邊界,這是需要進行添加element操作
  • 4)括號,這是最麻煩的一部,這裏有一個比較坑的地方是需要注意括號嵌套括號的情況,所以使用了下面的一段代碼,接着便是遞歸。
int flag = 0;
				while (1) {
					if (s[j_tmp] == '(') {
						flag++;
					}
					if (s[j_tmp] == ')') {
						flag--;
					}
					if (flag == 0) {
						j_tmp++;
						break;
					}
					j_tmp++;
				};
  • 5)字符遍歷越界,這裏也是需要判斷處理的。

這道題還是花了很長時間才做出來的,如果再考場上的話,拿不到滿分,能解決還是很happy的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章