Cod sursa(job #319515)

Utilizator madlexeicar md madlex Data 31 mai 2009 22:26:54
Problema Bool Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 8.55 kb
#include <iostream>
#include <stdlib.h>
#include <fstream>

using namespace std;

#define TRUE 1
#define FALSE 0

//#define DTEST

int main();
int _tmain(int argc, char* argv[])
{
	return main();
}
	//	BINARY TREE
	enum NODETYPE
	{
		NOT = 1,	//	operation = NOT
		OR,			//	operation = OR
		AND,		//	operation = AND
		VALUE,		//	VALUE - variable
		CT_VALUE	//	CT_VALUE - variable
	};

	const char * nodetypes[] = 
	{
		"",
		"NOT",
		"OR",
		"AND",
		"VALUE",
		"CT_VALUE"
	};

	struct NODE
	{
		//	Constructor
		NODE()
			: type (VALUE)
			, iVal(-1)
			, left(NULL)
			, right(NULL)
			, up(NULL)
		{;}

		//	Members
		NODETYPE		type;	//	NODE TYPE

		union{
			int			iVal;	//	index in vals[] | NODETYPE::VALUE
			int			value;	//	value			| NODETYPE::CT_VALUE
			int			prior;	//	priority		| NODETYPE::NOT, AND, OR 
		};

		NODE			*left;	//	left  node
		NODE			*right;	//	right node
		NODE			*up;	//	upper node (parent)
	};


	//	GLOBALS
	NODE * root(NULL);	//	binary tree
	char expr[1001]={0};//	unparsed expression
	char vars[101]={0};	//	variable names
	char vals[40]={0};	//	variable values (A - Z)
	int  N(0);			//	number of variables

	#define SETVARVALUE(char_val,value) vals[char_val-'A'] = (value)
	#define GETVARVALUE(char_val) (vals[char_val-'A'])
	#define ISOPNODE(node) (node->type >= NOT && node->type <= AND)
	#define ISVALNODE(node) (node->type == CT_VALUE || node->type == VALUE)

int evaluate_tree(NODE * node);

#ifdef DTEST
	void print_spaces(int spaces)
	{
		if( !spaces )return;
			printf("-");
		while(spaces-- > 0)
			printf(" ");
	}
	void print_tree(NODE* root,char ctype,int level,int evaluate = 1)
	{
			print_spaces(level*2);
			printf("%c:%s",
				ctype,
				nodetypes[root->type]);

			//	values
			if( root->type == VALUE )
				printf(" %c=%d ",
					root->iVal,
					GETVARVALUE(root->iVal));
			else
			//	constants
			if( root->type == CT_VALUE )
				printf(" %s ",
					root->value ? "TRUE":"FALSE");
			else
			//	operators
			if( ISOPNODE(root) )
				printf(" prior:%d",
					root->prior );\
			else
			throw;	//	unknown node

			printf("\tEV: %d",evaluate_tree(root));
			printf("\n");

		if( root->left ) print_tree(root->left,'L',level+1);
		if( root->right) print_tree(root->right,'R',level+1);
	}
#endif//DTEST

NODE * select_node( const char * word, int cch )
{
		//	New binary NODE
		NODE* node = new NODE;

		if( cch < 0 || cch == 0 ) throw;//	safety
		
			//	Select type
			//	OPERATIONS
			if( strcmp(word,"AND") == 0 )
			{
				node->type	= AND;
				node->prior	= 1;
			}else 
			if( strcmp(word,"OR") == 0 )
			{
				node->type	= OR;
				node->prior	= 0;
			}else
			if( strcmp(word,"NOT") == 0 )
			{
				node->type	= NOT;
				node->prior	= 2;
			}else
			//	VALUES
			if( strcmp(word,"FALSE") == 0 )
			{
				node->type	= CT_VALUE;
				node->value = 0;
			}else
			if( strcmp(word,"TRUE") == 0 )
			{
				node->type	= CT_VALUE;
				node->value = 1;
			}else
			//	VARIABLE
			{
				//	failure
				if( cch != 1 )
					throw;	//	variables can only be one char long

				node->type = VALUE;
				node->iVal = word[0];
			}

	return node;
}

int evaluate_tree(NODE * node)
{
	if( node->type == NOT )
	{
		NODE * val;

		if( node->left != NULL )
		{
			val = node->left;
			if( node->right != NULL )
				throw;//	NOT has only one operand
		}else
		if( node->right != NULL )
		{
			val = node->right;
		}else
			throw;	//	no operands defined

		return !evaluate_tree(val);
	}else
	if( node->type == AND )
	{
		return evaluate_tree(node->left) && evaluate_tree(node->right);
	}else
	if( node->type == OR )
	{
		return evaluate_tree(node->left) || evaluate_tree(node->right);
	}else
	if( ISVALNODE(node) )
	{
		if( node->left != NULL ||
			node->right != NULL )
			throw;	//	value nodes should not have descendants

		if( node->type == CT_VALUE )
				return node->value;
		else	return GETVARVALUE(node->iVal);
	}

	throw;
	return 0;
}

//	Construct Binary TREE
const char *parse_expr(const char * expr,NODE *& root)
{
	int iword;			//	index of current word char
	char word[10];		//	no words must exceeed 4 chars
	const char * seek;	//	movable ptr to expresion
	NODE * node;		//	current node
	NODE * prevnode;	//	previous node

	//	Initialize parsing
	seek = expr;		//	init seeker
	prevnode = NULL;

	while( *seek != '\0' && *seek != ')' )
	{
		//	trim
		while( *seek == ' ' ) seek++;

			//	SUBEXPRESION
			if( *seek == '(' )
			{
				NODE * subroot;
				seek = parse_expr(seek+1,subroot);

				if( subroot )
					if( prevnode == NULL )
					//	No previous node, mark subexpresion as previous
						prevnode = subroot;
					else
					//	Bind to the right of the previous node
					{
						if( ISVALNODE(prevnode) )
							throw;	//	previous node followed by a subexpression

						if( prevnode->right != NULL )
							throw;	//	previous node operation has full slots (safety)

						prevnode->right = subroot;
					}

				//	jump to next iteration
				continue;
			}

		//	Read word
		iword = 0;
		while(
			*seek != '\0' &&
			*seek != ' '  &&
			*seek != '('  &&
			*seek != ')'  &&
			iword < int(sizeof(word)) )
			word[iword++] = *seek++;

			if( iword == 0 )
				break;	//	no more readable words

			//	failure
			if( iword == sizeof(word) )
				throw;

			//	trucate
			word[iword] = 0;

		//	Select node based on word
		node = select_node(word,iword);

			if( node->type == NOT )
			//	NOT
			{
				if( prevnode != NULL )
				if( prevnode->left == NULL )
					prevnode->left = node,
					node->up = prevnode;
				else
				if( prevnode->right == NULL )
					prevnode->right = node,
					node->up = prevnode;
				else
					throw;	//	slots are full
			}else
			if( ISOPNODE(node) )
			//	OPERATION
			{
				if( prevnode )
				{
					NODE * seek = prevnode;

					//	Search for an operand with a HIGHER priority
					while(seek->up != NULL)
					{
						if( ISOPNODE(seek->up) == FALSE )
							throw;	//	upper value node isn't an operator

						if( node->prior > seek->up->prior )
						{
							NODE * save = seek->up->right;
							//	Inject
							seek->up->right = node;
							node->up		= seek->up;
							node->left		= save;
							save->up		= node;

							seek = NULL;
							break;
						}

						seek = seek->up;
					}

					if( seek != NULL )
					//	add operator on the top of the stack
					if( prevnode->up != NULL )	//	previous value has a parent
					{
						node->left = seek;
						seek->up   = node;
					}else
					//	Operator will be on the top of the stack
					{
						node->left	 = prevnode;
						prevnode->up = node;
					}
					
				}else
				if( node->type != NOT )
					throw;	//	no previous operator for NOT
			}else
			//	VALUE
			{
				if( prevnode )
				{
					if( ISVALNODE(prevnode) )
						throw;	//	previous node is another value

					//	Add value to the left (operand should be NOT)
					if( prevnode->left == NULL )
						prevnode->left = node,
						node->up = prevnode;
					else
					//	Add value to the right (to the previous operatop)
					if( prevnode->right == NULL )
						prevnode->right = node,
						node->up = prevnode;
					else
						throw;	//	op slots are full
				}
			}

			//	Mark previous node
			prevnode = node;

	}//	while(seek)

	//	trim (safety)
	while( *seek == ' ' ) seek ++;

	//	jump over ')'
	if( *seek == ')' ) seek ++;	

		//	walk-up root
		root = prevnode;

		if( root )
		while( root->up != NULL )
			root= root->up;

	return seek;
}

int main()
{
	//	Open & Start
	ifstream in("bool.in");

	//	READ
	in.get(expr,1001);in.get();		//	expresion
	in >> N;						//	number of vars
	int i(0);						//	variables
	while(i < N)
	{
		in >> vars[i],				//	read variable name
		vars[i] = toupper(vars[i]);	//	make sure is UPPERCASE
		i++;						//	next
	}

	//	Zero-out values
	for(i = 0;i <= int('Z'-'A'); i++)
		vals[i] = 0;

	//	Parse expression
	NODE * root(NULL);
	parse_expr(expr,root);

#ifdef DTEST
		//	Printout Expression
		printf("%s\n",expr);
		print_tree(root,'T',0);
#endif//DTEST

	ofstream out("bool.out");

		//	Switch vars
		for( i = 0 ; i < N ; i ++ )
		{
			//	Switch
			SETVARVALUE(vars[i],1-GETVARVALUE(vars[i] ));
			out << ((evaluate_tree(root) != 0)? 1:0);

#ifdef DTEST
			printf("Switching: %c (before:%d after:%d)\n",
				vars[i],
				!GETVARVALUE(vars[i]),
				GETVARVALUE(vars[i]));

			print_tree(root,'T',0);
#endif//DTEST

		}

	//	Exit & Close
	out.close();
	in.close();
	return 0;
}