UVa 817 According to Bartjens 题解

Posted alrond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 817 According to Bartjens 题解相关的知识,希望对你有一定的参考价值。

难度:β

建议用时:40 min

实际用时:4 h

题目:??

代码:??

 

这题有两个坑点首先要注意:

1)对于 “2000=” 要特判。应该判为 “IMPOSSIBLE”

2)枚举顺序为 “*+-” 然后是数字。

 

好了。这题的 DFS 过程很简单了。主要的是怎样计算一个字符串多项式(不带除号的)。

代码链接:??(这里我把除号带上了,原理跟减号一样的)

 

从最简单的加法开始。

1+2+3

怎样计算上面的式子?

我选择用递归。

从左到右(不是遍历,这里因该有一个区间)查看当前区间里的每一个元素,如果是 “+”,就把左右分开,分别调用后相加返回。

大致是这样的:

1 double calculate(int l, int r, string n_str) {
2     for (int i = l; i < r; i++) 
3         if (n_str[i] == +) 
4             return calculate(l, i, n_str) + calculate(i+1, r, n_str);
5 }

这是伪码,没有真实作用。(真?代码在上面的链接里)

注意,这里我们实际上是在带括号计算。举个例子:

1+2+3+4

如果这时从 1 和 2 之间的加号分开,那么实际上下面的过程是分别算两边的代数值。

(1)+(2+3+4)

不难发现,这样一来加法和乘法都好说,但是如果遇到间伐或除法就麻烦了。

1-2+3+4 = (1)-(2+3+4)

这显然是不对的。怎么办呢?干脆模拟一下,变个号。

1-2+3+4 = (1)-(2-3-4)

具体到代码就是:

1 if (n_str[i] == -) {
2     int j = i+1;
3     while (j != n_str.size()) { // 下面把后面的符号反过来。
4         if (n_str[j] == -) n_str[j] = +;
5         else if (n_str[j] == +) n_str[j] = -; // 注意 else,否则就白费功夫了。
6         j++;
7     } 
8     return calculate(l, i, n_str) - calculate(i+1, r, n_str);
9 }

乘法和除法的处理是类似的。但是既然乘除法的优先级比加减法高,那么就应该先从加减法剖开,后从乘除法剖开。乘除法要在最后计算。

另外,如果发现式子里没有任何符号了,说明这时处理的是数字。直接计算返回就好了。

注意:小心在做除法时溢出。最好用浮点数记录中间值。

 

上面分析了计算,下面就来看主算法。

 

这里的主算法很简单,不啰嗦,上代码:

 1 bool dfs(int cur_d, int cur_idx, bool ok) {
 2     if (cur_idx == str.size()) {
 3         if (try_cal(cur_d)) {
 4             output(cur_d);
 5             return true;
 6         }
 7         return false;
 8     }
 9     bool update = false;
10     for (int i = 0; i < 4; i++) {
11         if (i != 3 && ok) {
12             temp[cur_d] = oprt[i];
13             if (dfs(cur_d+1, cur_idx, false)) update = true;
14         }
15         if (i == 3) {
16             temp[cur_d] = str[cur_idx];
17             if (dfs(cur_d+1, cur_idx+1, true)) update = true;
18         }
19     }
20     return update;
21 }

我在调用时加入一个 Bool 值,表示可不可以在这一层加上符号。显然如果上一层是符号,这一层就不能用符号。开始调用时设为 false,因为第一个位置也不能用符号。

这样可以保证枚举时不会出现连续两个符号的情况。

 

一旦枚举出一种情况,立刻进行判断是否合法,然后输出。这没什么好说的。

判断有两种:一要确保代数和为 2000, 二要符合代数式的规矩,就是数字除 0 本身外不能以 0 开头(012),0 不能在开头连续多次出现(000),

最后一位不能是符号(12*),第一位也不能是符号(+123)(虽然这实际上是合理的,但是题目规定不能这样)。

1 bool qualify(string n_str) {
2     for (int i = 0; i < n_str.size(); i++) {
3         if (i == (int)n_str.size()-1 && is_operator(n_str[i])) return false; 
4         if (!i && n_str[i] == 0 && !is_operator(n_str[i+1])) return false; 
5         if (!i && is_operator(n_str[i])) return false; 
6         if (is_operator(n_str[i-1]) && n_str[i] == 0 && !is_operator(n_str[i+1]) && i != (int)n_str.size()-1) return false; 
7     }
8     return true;
9 }

这一段的调试很重要。上面计算的调试也很重要。大多数时间都应该花在调试这两个函数上面。

 

这样以来,这题就搞定了。思路并不难,主要是调试比较多。因为我是第一次写多项式的计算函数,所以在这上面花的时间比较多。

 

2018-01-29

以上是关于UVa 817 According to Bartjens 题解的主要内容,如果未能解决你的问题,请参考以下文章

English - according to 的用法说明

How to generate file name according to datetime in bat command

The remote certificate is invalid according to the validation procedure

Attribute class invalid for tag present according to TLD

Struts的莫名问题解决方法:Attribute class invalid for tag present according to TLD

According to TLD or attribute directive in tag file, attribute value does not accept any expressions