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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nimabide_01/article/details/78817920

原题边幅很长,这里就不贴出来了,落谷有原题,不清楚的可以去看看

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

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

 

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

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





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

那么接下来的任务就很明确了,就是一个个实现三大系统

 

我们读到的数据是字符串,字符串是不方便直接处理的,所以需要输入系统的数据提取功能,把字符串的有用的同类型数据转化成一个个数组存取,具体怎么提取,还要看接下来编译与判断系统需要的是字符串中的哪些信息。在本题目中,我把一行字符串看成由以下四类数据组成。

 

字符串开头非FEO(n^w)这行不需要进行编译和判断,只需要把w提取出来就行了。

stringF型(即开头为FE型以此类推)时才会有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;
}
 




这就是判断系统的原理了。

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

那么剩下来的就是数据的提取了,也就是输入系统的部分,我采用了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;
}


 



                                    
展开阅读全文

没有更多推荐了,返回首页