zoukankan      html  css  js  c++  java
  • 找Bug(Bug Hunt)[UVA1596]

    UVA 1596 BugHunt,ACM/ICPC Tokyo2007时间限制 3000ms 内存限制 128MB

    https://vjudge.net/problem/UVA-1596

    这题是书上第五章的习题5-9,按照惯例书上的题就不贴详细的样例输入输出和题目描述了。

    这个题首先要考虑的是题意。题目要求模拟一段程序的执行,而所执行的程序本身非常简单,操作对象是数组,数组只有赋值语句和定义语句。所以可以分开考虑赋值和定义语句;对于定义语句,我们就需要为当前执行的程序段构造一个概念上的“数组”。对于赋值语句,需要考虑左右操作数。除此之外,需要注意的地方还有,数组的下标很有可能是另一个表达式(在本题中是另一个数组的值),并且数组的下标越界或者使用了未初始化的值,都是要求输出“错误”的。

    注意到这题并非需要构造一个完整的数组,因为题目要求数组的下标最大值能达到$2^{31}-1$,如果使用malloc或者new运算符在堆内存分配一个完整的数组,一是时间上不可能很快;更重要的是,可用的堆内存并不够(一般情况下在OJ中只能使用128MB的内存)。所以需要另辟蹊径。因为程序很短,使用了的数组元素有限,因此可以使用STLmap这一容器,将使用的元素进行映射(从下标到值的一个映射;一般来说,数组本身就是简单的一对一映射关系)。map容器的内部实现是红黑树,其一般操作时间为$O(lgn)$,虽然不如直接用下标访问的数组和散列表的$O(1)$时间快,但也是可以接受的。至于要求判断是否越界,则很简单,只要对这个“数组”增加一个长度的属性来存放定义时数组的长度,在每次赋值操作时检查是否越界即可。因此我在这里定义了一个结构体arrayinfo,用来存放每次新建的一个“数组”;而判断是否初始化(也就是是否赋值)也比较简单,没有赋值,则这个map中没有这个对应关系,也就是利用find()函数返回的是mapend()迭代器。经过一次赋值后,利用insert()方法插入元素,则可以表示这个下标对应的值被“初始化”了。

    上面是解决这个问题的一个总体的思路:选择map这一数据容器来模拟程序中的数组。下面则主要说明一下一些细节性的问题:

    一是要考虑如何创建一个“数组”。题目中的“数组”名只有一个英文字母,因此可以直接使用其ASCII码来作为下标进行定位,一旦从输入中得到定义“数组”的行为,则在arrayset这个数组中,以其数组名作为下标进行访问,用new运算符新建一个arrayinfo并关联到arrayset上。如果考虑的更符合实际一点,“数组”名字可能是一个串,那就还是需要使用map这一容器将“数组名”与实际的数组对应,具体操作便是使用一个map<string, map<int, int> * >

    第二个问题就是如何解析嵌套的数组。从一般的思维上理解,便是从外向内扒的一个过程,所以很容易写出一个递归的方法:当表达式只是常数时,作为递归出口;否则脱去最外层的数组记号,将内层的表达式继续传给自身解析,直到解析到递归出口为止。当然非递归化也是可以的,就是需要手动使用一个栈。至于写入数组的值也很简单,只要稍作修改,利用上述思路得到对应的迭代器,然后通过迭代器修改值即可。

    第三个问题便是如何处理输出了。题目要求只要找到一行错误的代码,就要输出,并跳过余下的代码。我使用的是设置返回值的方法(也是传统的C/C++处理方法),利用返回代码判断是否出现错误,如果出现错误利用空循环跳过,直到读取到当前程序结束为止。因为UVA支持C++11,所以别人的代码也有直接使用try catch的结构化异常处理。从一个最早是接触VB.Net的视角来看,在这里使用异常会使得思路会显得更为清晰,这也是很多语言支持结构化异常处理的原因吧(虽然在Effective C++中,并不建议对C++使用异常)。

    最后附上我的C++实现(可能是使用new delete使得效率略低,在题目输入下花费了10ms的时间):

      1 #include<iostream>
      2 #include<map>
      3 #include<string>
      4 #include<stack>
      5 using namespace std;
      6 struct arrayinfo
      7 {
      8     map<int, int> data;
      9     size_t length;
     10     arrayinfo(size_t len) :length(len)
     11     {
     12     };
     13 };
     14 arrayinfo * arrayset[256] = { 0 };
     15 int exeline = 0;
     16 
     17 int getvalue(const string & exp)
     18 {
     19     //cout << "  " << exp << endl;
     20     if (exp[0] >= '0'&&exp[0] <= '9')
     21         return atoi(exp.c_str());
     22     size_t begin = exp.find('[');
     23     int id = getvalue(exp.substr(begin + 1, exp.length() - begin - 2));
     24     if (id == -1)return -1;
     25     if (id >= arrayset[exp[0]]->length)
     26     {
     27         //subscript out of range
     28         cout << exeline << endl;
     29         return -1;
     30     }
     31     map<int, int>::iterator it = arrayset[exp[0]]->data.find(id);
     32     if (it == arrayset[exp[0]]->data.end())
     33     {
     34         //uninitialized variable
     35         cout << exeline << endl;
     36         return -1;
     37     }
     38     return it->second;
     39 }
     40 int setvalue(const string & exp, int value)
     41 {
     42     //cout << "  " << exp << endl;
     43     size_t begin = exp.find('[');
     44     int id = getvalue(exp.substr(begin + 1, exp.length() - begin - 2));
     45     if (id == -1)
     46         return -1;
     47     if (id >= arrayset[exp[0]]->length)
     48     {
     49         //subscription out of range
     50         cout << exeline << endl;
     51         return -1;
     52     }
     53     map<int, int>::iterator it = arrayset[exp[0]]->data.find(id);
     54     if (it == arrayset[exp[0]]->data.end())
     55         //not found, means first time to assign value
     56         arrayset[exp[0]]->data.insert(pair<int, int>(id, value));
     57     else
     58         it->second = value;
     59     return 0;
     60 }
     61 
     62 int eval(const string & str)
     63 {
     64     arrayinfo * tmparray;
     65     //determine whether it is declaration or assignment
     66     if (arrayset[str[0]] == 0)
     67     {
     68         //it has not be declared .
     69         tmparray = new arrayinfo(atoi(str.c_str() + 2));        //offset one letter and a '['
     70         arrayset[str[0]] = tmparray;
     71     }
     72     else
     73     {
     74         size_t aoffset = str.find('=');
     75         int r = getvalue(str.substr(aoffset + 1, str.length() - aoffset));
     76         if (r == -1)
     77             return -1;
     78         return setvalue(str.substr(0, aoffset), r);
     79     }
     80     return 0;
     81 }
     82 
     83 
     84 
     85 int main()
     86 {
     87     //freopen("input.txt", "r", stdin);
     88     string buffer;
     89     int err = 0;
     90     bool sdot = false;
     91     while (cin >> buffer)
     92     {
     93         //reach a end , clear memory.
     94         if (buffer[0] == '.')
     95         {
     96         Clear:
     97             if (sdot == true)
     98                 break;
     99             sdot = true;
    100             for (int i = 0; i < 256; i++)
    101                 if (arrayset[i] != 0)
    102                 {
    103                     delete arrayset[i];
    104                     arrayset[i] = 0;
    105                 }
    106             exeline = 0;
    107             if (err != -1)
    108                 cout << "0" << endl;
    109             continue;
    110         }
    111         sdot = false;
    112         ++exeline;
    113         err = eval(buffer);
    114         //cout << " " << err << endl;
    115         if (err == -1)
    116             for (;;)
    117             {
    118                 cin >> buffer;
    119                 if (buffer[0] == '.')
    120                     goto Clear;
    121             }
    122     }
    123     return 0;
    124 }
  • 相关阅读:
    c 中 static 关键字的作用
    关于声明变量关键字 extern 的搜索知识点
    思考在路上-虚拟机redhat系统安装tools
    一个小程序猿思考之路-头文件中#ifndef/#define/#endif作用和用法
    const 修饰的小看点(自己积点小知识)
    用css3实现闪烁效果
    icon font
    跟踪对象属性值的修改, 设置断点(Break on property change)
    setTimeout(fn, 0)引发的JavaScipt线程的思考
    "float: left;" div 不换行显示
  • 原文地址:https://www.cnblogs.com/ggggg63/p/6665607.html
Copyright © 2011-2022 走看看