17年提高组的原题,相当有练习的价值。
题目
来直接切切入正题。
这个题就是个大模拟,难于处理的原因在于需要注意的细节比较多。只要挑选好模拟的数据结构,处理好细节问题,这道题就可以A掉了。
大致设想
为了模拟循环的嵌套关系,数据结构上选择先进后出的栈结构。 考虑到在计算嵌套层数同时还需要判定循环变量是否重复。所以,需要同时维护两个栈,一个统计层数,一个统计变量。
(有一个需要注意的点,就是在读入的时候,最好不要使用字符,而是用字符串,可以避免一系列的扯皮问题。)
开始模拟
- 每组数据,读入行数和复杂度字符串,从字符串中提取指定复杂度。(注意,复杂度的提取有两种情况,不是O(1)时还需要注意指定复杂度可能是多位数)
- 每一行数据,先读第一个字符,
是E则
弹栈并继续 ,若栈已经清空不能弹栈,说明出现了额外结束的情况,应标记错误。 (注意弹栈不要让栈顶为负RE警告)
是F则:-
继续读入循环变量并判定重复并记录,重复则标记错误。
-
读入循环始末,判断并计算该层的复杂度贡献。共可能有四种情况:
- 前数后数,判断大小,前小后大,常数;前大后小,无效。
- 前n后n,常数
- 前数后n,一个标准的循环,复杂度指数指数加一。
- 前n后数,n很大,所以无效。
在计算这里的复杂度时,应该由上一层继承而来。
- 复杂度常数时,指数不变,照抄上一位
- 复杂度n时,指数加一,抄上一位并加一。
- 无效复杂度时,定为负无穷,令后面的循环一并无效。
(需要注意的是:由于栈顶从0开始计数,照抄上一位时需要判定是否为第一位,当然,从1开始计数可以避免这个问题。)
-
统计答案,令当前最高统计复杂度与改位复杂度取大
-
栈顶向前移动。
-
- 每一行数据,先读第一个字符,
易错点总结
WA血泪史,划重点!!!
1 输入使用字符串代替字符.
2. 弹栈时注意栈顶不要减为负数
3. 数字可能不止一位
4. 记栈时注意首元素没有前一位
代码
C:
#include<stdio.h>
#include<string.h>
#define N 200
#define INF 1 << 30
int stack[N]; //统计层数
char cstack[N]; //统计变量
char ch[20],ch2[20];
//检查数组中是否包含元素k
bool check(char ch[],int len,char k)
{
for(int i = 0;i < len;i++)
{
if(ch[i] == k)
{
return true;
}
}
return false;
}
//字符串转数字
int getNumber(char ch[])
{
int num = 0;
for(int i = 0;i < strlen(ch);i++)
{
num = num * 10 + ch[i] - '0';
}
return num;
}
int max(int a,int b)
{
return a > b ? a : b;
}
int main()
{
int T; //组数
int num; //给定复杂度
int ma; //统计复杂度
int n; //每组行数
int top; //栈顶
char a,b; //循环始末
bool flag; //错误标记
//读入组数
scanf("%d",&T);
while(<