首先,我们自然而然联想到表达式求值的一道题,只要将元素符号转化为数字,再在分子式内加上加号和乘号就可以了。当然,这样做肯定费时费力,所以我们将那道题目的栈结构改变一下。
几个元素符号看着很不顺眼,所以我们将他们转化成值,即首位和末位按权展开:
xxxxxxxxxx
function hash(s:string):longint;
begin
if length(s)=1 then exit(ord(s[1])-64)
else exit((ord(s[1])-64)*100+ord(s[2])-96);
end;
读入部分很简单
xxxxxxxxxx
while true do
begin
readln(st);
if st='END_OF_FIRST_PART' then break;//结束了就退出
k:=pos(' ',st);
val(copy(st,k+1,length(st)),m);//数字部分
mass[hash(copy(st,1,k-1))]:=m;//定义原子质量
end;
然后,正文部分如何展开呢?
我们有如下步骤:
第一步,如果遇到左括号,直接进栈,等级
第二步,如果遇到大写字母,向后寻找还有没有小写字母和数字,并得到这些东西。
第三步,如果遇到右括号,向后寻找还有没有数字,并得到这些东西。
然后出栈。
值得注意的是,如果得不到数字,则
xxxxxxxxxx
while true do
begin
readln(st);
fillchar(num,sizeof(num),0);//初始化
w:=0;//当前级别
if st='0' then break;//完成了就退出
flag:=true;
st:='('+st+')';//方便最后的处理
for i:=1 to length(st) do
begin
if st[i]='(' then//进栈
begin
inc(w);
num[w]:=0;
end;
if st[i] in ['A'..'Z'] then//碰到元素符号
begin
if st[i+1] in ['a'..'z'] then name:=st[i]+st[i+1]
else name:=st[i];//得到完整名称
if mass[hash(name)]=-1 then//如果找不到这个元素符号
begin
writeln('UNKNOWN');
flag:=false;
break;
end;
j:=i+length(name);//继续向后寻找数字
cnt:=0;
while st[j] in ['0'..'9'] do
begin
cnt:=cnt*10+ord(st[j])-48;//和C++的快读差不多
inc(j);
end;
if cnt=0 then cnt:=1;//如果没有数字就是1
num[w]:=num[w]+mass[hash(name)]*cnt;//获得整个部分的质量分数
end;
if st[i]=')' then//出栈
begin
j:=i+1;//向后寻找数字
cnt:=0;
while st[j] in ['0'..'9'] do
begin
cnt:=cnt*10+ord(st[j])-48;
inc(j);
end;
if cnt=0 then cnt:=1;
dec(w);//更新上一级别的质量分数
num[w]:=num[w]+num[w+1]*cnt;
end;
end;
if flag=true then writeln(num[0]);//如果没有出现UNKNOWN情况
end;
xxxxxxxxxx
var mass,num:array[0..10000]of longint;
st,name:string;
flag:boolean;
k,i,j,cnt,w,m:longint;
function hash(s:string):longint;
begin
if length(s)=1 then exit(ord(s[1])-64)
else exit((ord(s[1])-64)*100+ord(s[2])-96);
end;
begin
fillchar(mass,sizeof(mass),255);
while true do
begin
readln(st);
if st='END_OF_FIRST_PART' then break;
k:=pos(' ',st);
val(copy(st,k+1,length(st)),m);
mass[hash(copy(st,1,k-1))]:=m;
end;
while true do
begin
readln(st);
fillchar(num,sizeof(num),0);
w:=0;
if st='0' then break;
flag:=true;
st:='('+st+')';
for i:=1 to length(st) do
begin
if st[i]='(' then
begin
inc(w);
num[w]:=0;
end;
if st[i] in ['A'..'Z'] then
begin
if st[i+1] in ['a'..'z'] then name:=st[i]+st[i+1]
else name:=st[i];
if mass[hash(name)]=-1 then
begin
writeln('UNKNOWN');
flag:=false;
break;
end;
j:=i+length(name);
cnt:=0;
while st[j] in ['0'..'9'] do
begin
cnt:=cnt*10+ord(st[j])-48;
inc(j);
end;
if cnt=0 then cnt:=1;
num[w]:=num[w]+mass[hash(name)]*cnt;
end;
if st[i]=')' then
begin
j:=i+1;
cnt:=0;
while st[j] in ['0'..'9'] do
begin
cnt:=cnt*10+ord(st[j])-48;
inc(j);
end;
if cnt=0 then cnt:=1;
dec(w);
num[w]:=num[w]+num[w+1]*cnt;
end;
end;
if flag=true then writeln(num[0]);
end;
end.