题目链接:http://poj.org/problem?id=1686
这道题是wls在51nod上直播时候挂出来的一道题,当时讲的是随机化来过这道题,我觉得随机化很好玩于是就去写了。但是。。。
这题的难点就不是随机化的样子,而是数据结构,表达式树。一开始并不知道有这么一个东西,然后翻到了紫书的P353,发现有这样一个模版,理解了一下,然后抄下来,自己写个计算表达式树的函数,即可。
表达式树代码在下面build_tree里面,自己模拟一边就知道他是个什么意思了。
然后就是,不用随机化也能过。。。(下面附上用随机数的代码)
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 10000;
int lch[maxn], rch[maxn];
char op[maxn];
int nc = 0;
int build_tree(char *s, int x, int y)
{
int i, c1 = -1, c2 = -1, p = 0;
int u;
if(y - x == 1)//仅一个字符,建立单独节点
{
u = ++nc;
lch[u] = rch[u] = 0;
op[u] = s[x];
return u;
}
for(int i = x; i < y; i++)
{
switch(s[i])
{
case '(': p++; break;
case ')': p--; break;
case '+': case '-': if(!p) c1 = i; break;
case '*': if(!p) c2 = i; break;
}
}
if(c1 < 0)//找不到括号外的加减号,就用乘除号
c1 = c2;
if(c1 < 0)//整个表达式被一堆括号括起来
return build_tree(s, x + 1, y - 1);
u = ++nc;
lch[u] = build_tree(s, x, c1);
rch[u] = build_tree(s, c1+1, y);
op[u] = s[c1];
return u;
}
int Count(int s)
{
switch(op[s])
{
case '+': return Count(lch[s]) + Count(rch[s]);break;
case '-': return Count(lch[s]) - Count(rch[s]);break;
case '*': return Count(lch[s]) * Count(rch[s]);break;
default : return op[s] >= '0' && op[s] <= '9' ? op[s] - 48 : op[s];
}
// if(op[s] == '+')
// return Count(lch[s]) + Count(rch[s]);
// else if(op[s] == '-')
// return Count(lch[s]) - Count(rch[s]);
// else if(op[s] == '*')
// return Count(lch[s]) * Count(rch[s]);
// else
// {
// if(op[s] >= '0' && op[s] <= '9')
// return op[s] - '0';
// else
// return op[s] - 'a' + 10;
// }
}
int main()
{
// freopen("in.txt", "r", stdin);
char str[10005], ch;
int T, t1, t2, len, i;
scanf("%d\n", &T);
while(T--)
{
nc = 0;
for(i = 0; (ch = getchar()) && ch != '\n'; i++)
if(ch != ' ')
str[i] = ch;
else
i--;
str[i] = '\0';
len = i;
build_tree(str, 0, len);
t1 = Count(1);
nc = 0;
for(i = 0; (ch = getchar()) && ch != '\n'; i++)
if(ch != ' ')
str[i] = ch;
else
i--;
str[i] = '\0';
len = i;
build_tree(str, 0, len);
t2 = Count(1);
if(t1 == t2)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
计算函数那我用了两种选择语句,为什么呢?因为这个出题人出的数据里面有空格,所以数组开小了,然后你就可能出现wa,tle,最好的情况当然是re的情况了,我就一直tle还怀疑是不是这个if效率太低?但是怎么想都想不懂。然后,毕竟poj嘛,discuss还是很齐全的,点进去一看,就发现了真相!@#¥%……
随机化过题的代码:(随机化次数由我里面的tmp决定,有的题目中想尽量降低错误率则把tmp增大知道逼近于时限为止)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stdlib.h>
#include<time.h>
using namespace std;
const int maxn = 10000;
int lch[maxn], rch[maxn], num[260];
char op[maxn];
int nc = 0;
int build_tree(char *s, int x, int y)
{
int i, c1 = -1, c2 = -1, p = 0;
int u;
if(y - x == 1)//½öÒ»¸ö×Ö·û£¬½¨Á¢µ¥¶À½Úµã
{
u = ++nc;
lch[u] = rch[u] = 0;
op[u] = s[x];
return u;
}
for(int i = x; i < y; i++)
{
switch(s[i])
{
case '(': p++; break;
case ')': p--; break;
case '+': case '-': if(!p) c1 = i; break;
case '*': if(!p) c2 = i; break;
}
}
if(c1 < 0)//ÕÒ²»µ½À¨ºÅÍâµÄ¼Ó¼õºÅ£¬¾ÍÓó˳ýºÅ
c1 = c2;
if(c1 < 0)//Õû¸ö±í´ïʽ±»Ò»¶ÑÀ¨ºÅÀ¨ÆðÀ´
return build_tree(s, x + 1, y - 1);
u = ++nc;
lch[u] = build_tree(s, x, c1);
rch[u] = build_tree(s, c1+1, y);
op[u] = s[c1];
return u;
}
int Count(int s)
{
switch(op[s])
{
case '+': return Count(lch[s]) + Count(rch[s]);break;
case '-': return Count(lch[s]) - Count(rch[s]);break;
case '*': return Count(lch[s]) * Count(rch[s]);break;
default : return op[s] >= '0' && op[s] <= '9' ? op[s] - 48 : num[op[s]];
}
}
int main()
{
char str1[10005], str2[10005], ch;
int T, t1, t2, len, i, tmp;
bool flag = 1;
scanf("%d\n", &T);
while(T--)
{
// srand((unsigned)time(NULL));
flag = 1;
tmp = 10;
for(i = 0; (ch = getchar()) && ch != '\n'; i++)
if(ch != ' ')
str1[i] = ch;
else
i--;
str1[i] = '\0';
for(i = 0; (ch = getchar()) && ch != '\n'; i++)
if(ch != ' ')
str2[i] = ch;
else
i--;
str2[i] = '\0';
while(flag && tmp--)
{
for(int i = 0; i < 256; i++)
num[i] = rand() % 10000;
nc = 0;
build_tree(str1, 0, strlen(str1));
t1 = Count(1);
nc = 0;
build_tree(str2, 0, strlen(str2));
t2 = Count(1);
if(t1 != t2)
flag = 0;
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
并不能用srand(),否则会RE。