【提高组NOIP2017】时间复杂度 题解 分治系统处理
2017-12-16 04:24
357 查看
原题边幅很长,这里就不贴出来了,落谷有原题,不清楚的可以去看看
------------------------------------------------------------------------------------------------------------
这是一道大模拟,我的方法是建立输入、编译和判断三大系统。
这三大系统用三个函数实现,分别是
void Input() //输入系统,专门读取数据并把字符串内的有价值数据提取出来
bool complite() //编译系统,对整组数据进行语法检查,返回true代表语法正确
bool work() //判断系统,符合时间复杂度返回true,否则返回false
-------------------------------------------------------------------------------------------------------------------
主要流程:
所以主函数是这样的:
----------------------------------------------------------------------------------------------------------------------------
那么接下来的任务就很明确了,就是一个个实现三大系统
我们读到的数据是字符串,字符串是不方便直接处理的,所以需要输入系统的数据提取功能,把字符串的有用的同类型数据转化成一个个数组存取,具体怎么提取,还要看接下来编译与判断系统需要的是字符串中的哪些信息。在本题目中,我把一行字符串看成由以下四类数据组成。
字符串开头非F即E,O(n^w)这行不需要进行编译和判断,只需要把w提取出来就行了。
当string为F型(即开头为F,E型以此类推)时才会有i
x y
了解了字符串的数据组成后,那么数据的提取也就变得很简单了:
开出这下面四个数组
1. 用于记录第i行的字符串类型的数组type[]
2. 用于记录第i行的计数变量名的数组ch[]
3. 用于记录第i行的计数变量的值的数组x[]
4. 用于记录第i行的循环边界值的数组y[]
-------------------------------------------------------------------------------------------------------------------------
编译系统用到了其中的type[]和ch[]数组,看看其工作原理吧:
对应代码:
------------------------------------------------------------------------------------------------------------------------------------
而判断系统用到了type[],x[], y[],由于流程较长,就用伪代码粗略讲下,稍后会给全部程序
能进入判断系统,说明所有语句都是合法的,每一个F都会有与其匹配的E
对于计算循环体的时间复杂度,我们可以采用递归的方式
计算出循环体的时间复杂度后,可用来与题目标出来的时间复杂度向比较看是否匹配
这就是判断系统的原理了。
-------------------------------------------------------------
a014
----------------------------------------------------------------------------------------------------------------
那么剩下来的就是数据的提取了,也就是输入系统的部分,我采用了getline()的方式去读取,事实上从字符串中提取数据的方法多种多样,我的并不一定是最好的,这个大家可以到网上去查大神的操作,不过这里我还是得贴出全部代码,不然以上讲的程序也不成整体。
-------------------------------------------------------------------------------------------------------------------
全代码:
------------------------------------------------------------------------------------------------------------
这是一道大模拟,我的方法是建立输入、编译和判断三大系统。
这三大系统用三个函数实现,分别是
void Input() //输入系统,专门读取数据并把字符串内的有价值数据提取出来
bool complite() //编译系统,对整组数据进行语法检查,返回true代表语法正确
bool work() //判断系统,符合时间复杂度返回true,否则返回false
-------------------------------------------------------------------------------------------------------------------
主要流程:
所以主函数是这样的:
int main() { cin>>t; for(int i=0; i<t ;i++){ //循环t次,每组输入一组数据 Init(); //该函数的作用为初始化所有数组与全局变量 Input(); //读入数据 /*编译成功就对数据进行判断并输出”Yes”或”No”,否则输出”ERR”*/ if(complite()){ if(work()) cout<<"Yes"<<endl; else cout<<"No"<<endl; else cout<<"ERR"<<endl; } return 0; }
----------------------------------------------------------------------------------------------------------------------------
那么接下来的任务就很明确了,就是一个个实现三大系统
我们读到的数据是字符串,字符串是不方便直接处理的,所以需要输入系统的数据提取功能,把字符串的有用的同类型数据转化成一个个数组存取,具体怎么提取,还要看接下来编译与判断系统需要的是字符串中的哪些信息。在本题目中,我把一行字符串看成由以下四类数据组成。
字符串开头非F即E,O(n^w)这行不需要进行编译和判断,只需要把w提取出来就行了。
当string为F型(即开头为F,E型以此类推)时才会有i
x y
了解了字符串的数据组成后,那么数据的提取也就变得很简单了:
开出这下面四个数组
1. 用于记录第i行的字符串类型的数组type[]
2. 用于记录第i行的计数变量名的数组ch[]
3. 用于记录第i行的计数变量的值的数组x[]
4. 用于记录第i行的循环边界值的数组y[]
-------------------------------------------------------------------------------------------------------------------------
编译系统用到了其中的type[]和ch[]数组,看看其工作原理吧:
对应代码:
bool complite() { /*先检查变量名,看有没有毛病*/ for(int i=1; i<n ;i++){ if(type[i] == _F){ if(var[ch[i]]) return false; //重复定义了变量 else{ var[ch[i]] = true;//建立变量 Steak[++top] = ch[i]-'a';//储存该层循环的变量 } } else if(type[i] == _E){ if(top >= 0) var[Steak[top--]] = false;//退出循环,销毁该层循环变量 } } /*检查F与E是否都匹配上*/ int steak = 0;//小F栈 for(int i=1; i<n ;i++){ if(type[i] == _F) steak++; if(type[i] == _E){ if(steak <= 0) return false; //E多了出来 steak--; } } if(steak > 0) return false; //有尚未匹配的F return true;//无语法错误,返回真 }
------------------------------------------------------------------------------------------------------------------------------------
而判断系统用到了type[],x[], y[],由于流程较长,就用伪代码粗略讲下,稍后会给全部程序
能进入判断系统,说明所有语句都是合法的,每一个F都会有与其匹配的E
对于计算循环体的时间复杂度,我们可以采用递归的方式
Int pos2; //全局变量,代表当前正在处理的行数 Int Jisuan(int pos) //pos表示计算的是第pos行循环的的时间复杂度 { pos2 = pos+1; If(第pos2行的字符串类型为E型){ pos2++; 根据第pos行的x与y的关系返回0或1; } If(第pos行循环并没有进入){ 跳过第pos行循环包含的所有循环并返回0; } Else{ 由第pos行的x和y关系算出该层循环本身固有的时间复杂度为1或n,并储存在now中 循环(只要第pos2行不是E型字符串){ Max = max(jisuan(各个子循环)) } } now += Max; return now; }
计算出循环体的时间复杂度后,可用来与题目标出来的时间复杂度向比较看是否匹配
Bool work() { int Max; //最大时间复杂度循环体的时间复杂度 循环(i 1:n){ If(第i行字符串为F类型){ Max = max(Max, jisuan(i)); i = pos2; } } If(Max == 规定时间复杂度) return true; Else return false; }
这就是判断系统的原理了。
-------------------------------------------------------------
a014
----------------------------------------------------------------------------------------------------------------
那么剩下来的就是数据的提取了,也就是输入系统的部分,我采用了getline()的方式去读取,事实上从字符串中提取数据的方法多种多样,我的并不一定是最好的,这个大家可以到网上去查大神的操作,不过这里我还是得贴出全部代码,不然以上讲的程序也不成整体。
-------------------------------------------------------------------------------------------------------------------
全代码:
#include <iostream> #include <string> #include <cstring> #define MAX 10000 #define N 9999999 using namespace std; enum Type{ _F, _E }; string data[MAX];//输入的数据 /*设第i行的语句为 "F i x y" 则以下全局变量的作用*/ int type[MAX]; //若type[i] = _F ,说明该行是以F开头的语句 int ch[MAX]; //用于记录第i行的计数变量名的数组 int x[MAX]; //用于记录第i行的计数变量的值的数组 int y[MAX]; //用于记录第i行的循环边界值的数组 /************************************************/ bool var[30];//变量表,0~25对应a~z,true表示变量已建立 int Steak[MAX];//F栈,用于编译系统,方便销毁变量 int top = -1; //栈顶指针 int time; //记录输入数据中要求的时间复杂度 int pos2; //正在处理的行数,用于判断系统 int t;//共有t组数据 int n;//该组数据有n行(实际上包括O(n^w)这行有n+1行) void Init() { memset(var, 0, sizeof(var)); memset(type, 0, sizeof(type)); memset(x, 0, sizeof(x)); memset(y, 0, sizeof(y)); memset(Steak, 0, sizeof(Steak)); memset(ch, 0, sizeof(ch)); time = 0; pos2 = 0; } void Input() { int temp = 0; int pos; cin>>n; n++; for(int i=0; i<n ;i++) { getline(cin, data[i]); if(data[i][1] == 'O'){ for(int j=4; j<data[i].size() ;j++) if(data[i][j]<='9' && data[i][j] >= '0') temp = temp*10 + data[i][j]-'0'; time = temp; } else if(data[i][0] == 'F'){ type[i] = _F; ch[i] = data[i][2]; pos = 4; temp = 0; while(data[i][pos] != ' '){ if(data[i][pos] == 'n'){ x[i] = N; } else{ temp = temp*10 + data[i][pos]-'0'; } pos++; } if(x[i] != N) x[i] = temp; temp = 0; pos++; while(pos < data[i].size()){ if(data[i][pos] == 'n'){ y[i] = N; } else{ temp = temp*10 + data[i][pos]-'0'; } pos++; } if(y[i] != N) y[i] = temp; } else if(data[i][0] == 'E'){ type[i] = _E; } } } bool complite() { /*先检查变量名,看有没有毛病*/ for(int i=1; i<n ;i++){ if(type[i] == _F){ if(var[ch[i]]) return false; //重复定义了变量 else{ var[ch[i]] = true;//建立变量 Steak[++top] = ch[i]-'a';//储存该层循环的变量 } } else if(type[i] == _E){ if(top >= 0) var[Steak[top--]] = false;//退出循环,销毁该层循环变量 } } /*检查F与E是否都匹配上*/ int steak = 0;//小F栈 for(int i=1; i<n ;i++){ if(type[i] == _F) steak++; if(type[i] == _E){ if(steak <= 0) return false; //E多了出来 steak--; } } if(steak > 0) return false; //有尚未匹配的F return true;//无语法错误,返回真 } int jisuan(int pos) { if(type[++pos2] == _E){ if(x[pos] != N && y[pos] == N){ pos2++; return 1; } else{ pos2++; return 0; } } int now = 0; int steak = 1; if(x[pos] > y[pos]){ //没进入循环 ,跳过所有循环并返回0 while(steak != 0){ if(type[pos2++] == _E) steak--; else steak++; } return 0; } int Max = 0; int temp = 0; if(x[pos] <= y[pos]){ //进入循环 if(x[pos] != N && y[pos] == N) now++; while(type[pos2] != _E){ temp = jisuan(pos2); if(temp > Max) Max = temp; } } pos2++; now += temp; return now; } bool work() { int Max = 0; for(int i=1; i<n ; i=pos2){ if(type[i] == _F){ pos2 = i; Max = max(Max, jisuan(i)); } } if(Max == time) return true; else return false; } int main() { freopen("text.in", "r", stdin); cin>>t; for(int i=0; i<t ;i++){ Init(); Input(); if(complite()) if(work()) cout<<"Yes"<<endl; else cout<<"No"<<endl; else cout<<"ERR"<<endl; } return 0; }
相关文章推荐
- NOIP 2017 提高组 时间复杂度___模拟
- 【jzoj5286】【NOIP2017提高A组模拟8.16】【花花的森林 】【时间倒流】
- NOIP2017提高组初赛题解
- 计蒜客 2017 NOIP 提高组模拟赛(一)题解
- NOIP 2017 Day1 题2: 时间复杂度 栈
- 5474. 【NOIP2017提高组正式赛】时间复杂度
- NOIP2017提高组初赛 个人理解+题解
- {题解}[jzoj4924]【NOIP2017提高组模拟12.17】向再见说再见
- JZOJ 5474. 【NOIP2017提高组正式赛】时间复杂度
- 【jzoj5338】【NOIP2017提高A组模拟8.25】【影子】【点分治】
- jzoj100048 【NOIP2017提高A组模拟7.14】紧急撤离 (网格图,分治,bitSet)
- 【JZOJ 5434】【NOIP2017提高A组集训10.30】Matrix
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- JZOJ 5415. 【NOIP2017提高A组集训10.22】公交运输
- JZOJ5437. 【NOIP2017提高A组集训10.31】Sequence
- [题解+总结]NOIP2013-2014提高组题目浅析
- NOIP 2017 时间复杂度
- [JZOJ5422]【NOIP2017提高A组集训10.25】天才绅士少女助手克里斯蒂娜
- JZOJ5360. 【NOIP2017提高A组模拟9.12】Shorten Diameter
- NOIP 2017题解(更新ing)