UVa 1596 Bug Hunt (string::find && map && 模拟)
题意 : 给出几组由数组定义与赋值构成的编程语句, 有可能有两种BUG, 第一种为数组下标越界, 第二种为使用尚未定义的数组元素, 叫你找出最早出现BUG的一行并输出, 每组以' . '号分隔, 当有两组输入都是' . '时结束程序
分析 : 由于错误的类型由题意所述的两种组成, 所以我们需要知道每个数组的长度与每个已经被赋值定义过的数组元素大小, 因此可以定义map<string, int> Info 来存储数组名和这个数组的大小两个信息, 在定义一个map<string, map<int, int>> arr 来储存数组内某个元素的具体的值。由于每一行的语句可以很复杂, 类似 a[B[a[0]]]=a[B[0]] 这样, 所以需要分步处理!这里的解决方案步骤如下, 都以 c[B[a[0]]]=a[B[0]] 为例
1、如果为定义语句, 则直接进行模拟和存储即可
2、如果为赋值语句,则将其按等于号分为左右两部分进行处理 (即 c[B[a[0]]] 和 a[B[0]] )
3、提取出左部分并且分为将要被赋值的数组名 和 其[ ]内的内容 (即 c 和 B[a[0]] )
4、提取出右部分全部 (即 a[B[0]])
5、如果需要处理的数组下标, 即[ ]里的元素就是数字的话则直接判断是否存在题目所述的两种BUG, 不存在则模拟正常存储过程
6、如果[ ]元素还是嵌套的数组, 可以发现这种情况的处理方法都是从里往外一个个全部找BUG并且转成对应的数字, 符合递归思想, 因此可以写一个递归模块check()来提取
7、将第三步提取出的[ ]中的内容丢进check()进行查错和转化 (即 check( B[a[0]] )
8、将第四步提取出的内容同样丢进check()进行查错和转化
9、若所有的check()都没毛病, 则复杂的语句将会变成——>数组名[数字] = 数字 这种形式, 进行模拟存储即可
技巧 : 其中有些操作可能会比较麻烦, 下面介绍几个函数
1、字符的分部可以使用string::find_first_of( 元素 )函数, 其返回的是在string中第一次找到元素的位置 和 string::substr(begin, len)来解决
2、判断语句是否有' = '号可以使用string::find(), 如果 其!=string::npos则说明存在
瞎搞 : 在做这种模拟题前需要仔细斟酌, 否则打出来之后可能花了很多时间却发现了重大的错误, 并且需要多想用什么进行存储能方便操作, 还有尽量进行模块化编程, 否则打出来后一旦出现BUG, 对着又长又臭的代码, 改错难度肯定很大!因此三思而后行啊!
#include<bits/stdc++.h> #define in 0 #define out 0 using namespace std; map<string, int> info; map<string, map<int, int> > arr; bool Error; // check中的标志,如果为true则说明已经存在BUG int check(string s) { if(isdigit(s[0])){ stringstream num(s); int k; num>>k; return k; }else{ string Inner = s.substr(s.find_first_of('[')+1, s.find_first_of(']')-s.find_first_of('[')-1); string name = s.substr(0, s.find_first_of('[')); int index = check(Inner); if(!info.count(name) || index==-1){ Error = true; return -1; }else{ if(index>=info[name]){ Error = true; return -1; }else{ if(!arr[name].count(index)){ Error = true; return -1; }else{ return arr[name][index]; } } } } } bool solve() { Error = false; string temp; int line = 0;//记录行数 int error_line = 0;//记录错误的行数 while(cin>>temp){ if(temp[0]=='.'){ if(!line) return false; else{ info.clear(); arr.clear(); printf("%d\n", error_line); return true; } } if(error_line != 0) continue;//如果已经找到错误的行数, 没必要进行下去 line++; if(temp.find('=') != string::npos){ string Left = temp.substr(0, temp.find_first_of('=')); string Right = temp.substr(temp.find_first_of('=')+1); string A = Left.substr(0, Left.find_first_of('[')); string B = Right.substr(0, Right.find_first_of('[')); string InA = Left.substr(Left.find_first_of('[')+1, Left.find_last_of(']')-Left.find_first_of('[')-1); int L = check(InA);//丢进check进行数字的转化 int R = check(Right); if(Error){//上面进行check后如果Error为true则说明找到BUG error_line = line; }else{ if(!info.count(A)){ error_line = line; }else{ map<int, int> temp2; if(L>=info[A] || L<0){ error_line = line; }else{ if(!arr.count(A)){ temp2[L] = R; arr[A] = temp2; }else{ arr[A][L] = R; } } } } }else{ string name = temp.substr(0, temp.find_first_of('[')); string index = temp.substr(temp.find_first_of('[')+1, temp.find_first_of(']')-1); stringstream num(index); int len; num>>len; info[name] = len; } } } int main(void) { #if in freopen("in.txt", "r", stdin); #endif #if out freopen("out.txt", "w", stdout); #endif while(solve()){} return 0; }