例题11-1 公共表达式消除 UVa12219

1.题目描述:点击打开链接

2.解题思路:第一步是构造表达式树,构造时可以利用一个map来记录出现的子树,并为之编号。例如,用(a,0,0)可以表示一个叶子a,用(b,3,6)表示根的名字是b,子树的编号分别是3,6的树。这样既可方便地得到最简表达式。本题总的时间复杂度为O(N*logN)。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

const int mx = 60000;
int T, rnd, cnt;
char expr[mx * 5], *p;
int done[mx];
struct Node
{
	string s;
	int ha, left, right;
	bool operator < (const Node&b)const//由于下面要用到map::count函数,所以必须要重载小于号
	{
		if (ha != b.ha)return ha < b.ha;
		if (left != b.left)return left < b.left;//哈希相同则比较出现的顺序
		return right < b.right;
	}
}node[mx];
map <Node, int>dict;//记录子树的编号
int solve()
{
	int id = cnt++;//从0开始编号
	Node&u = node[id];
	u.left = u.right = -1;
	u.s = "";
	u.ha = 0;
	while (isalpha(*p))
	{
		u.ha = u.ha * 27 + *p - 'a' + 1;//可以理解为27进制,a到z的编号为1到26
		u.s.push_back(*p);//将该子树的字母放入s
		p++;//向后扫描,遇到括号停止
	}
	if (*p == '(')//(L,R),递归处理左右子树
	{
		p++;//先跳过'('
		u.left = solve(), p++;//返回左子树编号,并跳过','
		u.right = solve(),p++;//返回右子树编号,并跳过')'
	}
	if (dict.count(u))
	{
		cnt--;//子树出现过,个数减少1
		return dict[u];//返回这颗子树的编号
	}
	return dict[u] = id;//如果这棵树是首次出现,给它编号
}
void print(int v)
{
	if (done[v] == rnd)printf("%d", v + 1);//已经输出过了,输出序号即可
	else
	{
		done[v] = rnd;//不需要对done数组初始化,只需要用这一轮特有的rnd标记即可
		printf("%s", node[v].s.c_str());//输出树根的字母
		if (node[v].left != -1)//含有左右子树
		{
			putchar('(');
			print(node[v].left);//递归输出左右子树
			putchar(',');
			print(node[v].right);
			putchar(')');
		}
	}
}

int main()
{
	freopen("test.txt", "r", stdin);
	scanf("%d", &T);
	for (rnd = 1; rnd <= T;rnd++)
	{
		dict.clear();
		cnt = 0;
		scanf("%s", expr);
		p = expr;//用指针p扫描expr
		print(solve());
		putchar(10);//打印换行符
	}
	return 0;
}
时间: 2024-11-10 13:31:45

例题11-1 公共表达式消除 UVa12219的相关文章

uva 12219 公共表达式消除

转自:http://blog.csdn.net/xl2015190026/article/details/51927559 题目大意: 见紫书p354 基本思路: 二叉树递归,解决超时问题就用map,虽然我不会写map,这是一个问题: 这个print之所以还是用一个done来标记是因为怕越界,如果用数组就得开的非常大,而且容易越界: 代码如下: #include<stdio.h> #include<iostream> #include<map> #include<

公共表达式消除 uva 12219

自己写的时候不知道怎么处理编号,看了别人的代码才发现可以预留编号,学习一个 今天才知道map需要处理好顺序才能正确查找 #include<iostream> #include<algorithm> #include<cstdio> #include<algorithm> #include<map> #include<cstring> using namespace std; #define LL long long #define m

sql server 公共表达式(CTE)的简单应用

现在做项目数据访问基本都会选择一种orm框架,它以面向对象的形式屏蔽底层的数据访问形式,让开发人员更集中在业务处理上,而不是和数据库的交互上,帮助我们提高开发效率:例如一些简单的insert.update,我们不需要写insert into...sql 语句,而是直接new一个实体对象,然后db.Insert(entity),看起来是那么清爽:像EF这样比较完善的orm,支持linq语法对数据库进行访问,写起来就更加爽了,有些人甚至认为开发人员可以不用会写sql语句了...但现实不会让你工作得那

[Inside HotSpot] C1编译器优化:条件表达式消除

1. 条件传送指令 日常编程中有很多根据某个条件对变量赋不同值这样的模式,比如: int cmov(int num) { int result = 10; if(num<10){ result = 1; }else{ result = 0; } return result; } 如果不进行编译优化会产出cmp-jump组合,即根据cmp比较的结果进行跳转.可以使用gcc -O0查看: cmov(int): push rbp mov rbp, rsp mov DWORD PTR [rbp-20],

C++11 里lambda表达式的学习

最近看到很多关于C++11的文档,有些是我不怎么用到,所以就略过去了,但是lambda表达式还是比较常用的,其实最开始学习python的时候就觉得lambda这个比较高级,为什么C++这么弱.果然C++增加这个东西. 语法 [ capture ] ( params ) mutable exception attribute -> ret { body }      (1) [ capture ] ( params ) -> ret { body }                       

sqlserver 公共表达式小体验

创建测试数据表 CREATE TABLE [dbo].[test]( [id] [int] IDENTITY(1,1) NOT NULL, [parent_id] [int] NULL, [agent] [bit] NULL, CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED ( [id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_R

C++11之lambda表达式

lambda表达式源于函数式编程的概念,它可以就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象.lambda表达式的类型在C++11中被称为"闭包类型",也可以理解为是一个仿函数(带operator()类),其语法形式如下: [capture] (params) opt -> ret {body;}; capture: 捕获列表: params: 参数列表: opt: 函数选项: ret: 返回值类型: body: 函数体. 一个简单的lambda表达式如下:

STL - C++ 11的Lambda表达式

Lambda始自C++ 11,是一种在表达式或语句内指定函数行为的定义式. 你可以定义函数行为作为对象,以inline实参的形式传给算法作为predicate(判断式). eg: std:transform(coll.begin(), coll.end(),  // source                      coll.begin(),                 // destination                      [](double d) {        

11.1.2 表达式树

二叉树是表达式处理的常用工具. 当我们输入一个表达式的时候:a+b*(c-d)-e/f ,那么给二叉树中的每个节点一个字符,这个二叉树可以构成我们所需要的表达式. 那么,我给你一个表达式后,你是如何建立一棵和这个表达式一样的树呢? 问题: 找到这个表达式中最后运算的符号. 代码: # include<cstdio> # include<iostream> # include<cstring> using namespace std; # define MAX 12345