您的位置:首页 > 其它

【提高组NOIP2017】时间复杂度 题解 分治系统处理

2017-12-16 04:24 357 查看
原题边幅很长,这里就不贴出来了,落谷有原题,不清楚的可以去看看

------------------------------------------------------------------------------------------------------------

这是一道大模拟,我的方法是建立输入、编译和判断三大系统。

 


这三大系统用三个函数实现,分别是

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;
}


 



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息