[数据结构][应用] 队列的应用 乘法分配律
以下“输入顺序排序”都为先输入的先输出
一
输入:
一个乘法,乘法由两个加减法组成,两个加减法之间由括号相隔、或者没有相隔
保证每一个变量由一个字母(包括大小写)组成
若一个加减法由两个及以上个变量组成,则用括号括起来,如(a+b+c)
若只有一个正变量组成,则没有括号;如果是一个负变量,则有括号
例如该乘法可以是a(a+b+c)、(a+b+c)a、(a+b-c)(b-c+d)、aa、(-a+b)(-a)
其中左边为被乘数,如a、(a+b+c)、(a+b-c)、a、(-a+b),右边为乘数,如(a+b+c)、a、(b-c+d)、a、(-a)
输出:
根据乘法分配律输出最终结果,分配成对的两个变量称之为对子,对子内部没有相隔,对子之间由加减'+'、'-'号隔开。
输出规则:
1. 对子内部的顺序为左边为被乘数所含的变量,右边为乘数所含的变量
2. 对子之间的顺序应该先由被乘数的输入顺序排序,相同被乘数再由乘数输入顺序排序。
3. 不处理一个对子是两个相同变量成对的情况,例如 aa
4. 不处理两个不同对子中变量相同的情况,例如 ab+ab+ba-ba
5. 如果第一个对子是正数,则不需要输出'+';如果为负数则应该输出'-'
样例1:
输入
a(a+b+c)
输出
aa+ab+ac
样例2:
输入
(a+b+c)a
输出
aa+ba+ca
样例3:
输入
(a+b-c)(b-c+d)
输出
ab-ac+ad+bb-bc+bd-cb+cc-cd
样例4:
输入
(b-c+d)(a+b-c)
输出
ba+bb-bc-ca-cb+cc+da+db-dc
样例5:
输入
aa
输出
aa
思路:
维护三个队列,分别是被乘数、乘数、积
被乘数、乘数队列的数据为两个字符,分别代表正负符号和变量名
积的队列数据为一个字符和一个字符串,字符代表正负符号,字符串代表两个变量名相乘
循环被乘数内嵌乘数,积的正负符号等于被乘数与成熟符号的异或,积的字符串等于被乘数与乘数字符串相加
细节点:
- 输入要分别处理被乘数(i = 0不为左括号)、乘数(i = queue.length - 1不为右括号)为单个正变量情况
- 输入要处理括号内第一个字符是变量还是负号的情况
1 #include <iostream> 2 #include <queue> 3 #include <string> 4 #include <utility> 5 6 #define cout std::cout 7 #define cin std::cin 8 #define endl std::endl 9 10 typedef std::queue<std::pair<char,char> > pair_char; 11 typedef std::queue<std::pair<char,std::string> > pair_string; 12 13 void read_queue (pair_char*,pair_char*); 14 void Distribution (pair_char,const pair_char*,pair_string*); 15 void print_ans (pair_string); 16 int main() { 17 pair_char Multiplicand; // left variable, sign and variable 18 pair_char Multiplier; // right variable, sign and variable 19 pair_string ans; 20 read_queue(&Multiplicand,&Multiplier); 21 Distribution(Multiplicand,&Multiplier,&ans); 22 print_ans(ans); 23 return 0; 24 } 25 void read_queue(pair_char* left,pair_char* right) { 26 std::string input; 27 bool flag = false; // if flag == false, input left; else input right 28 bool single_left = false; // if single_left = true, means that left is single variable 29 bool sign; // if sign == false, this variable is positive 30 std::pair<char,char> push_data; 31 32 cin >> input; 33 34 for(int i = 0;i < input.length();i++) { 35 if (input[i] == ')') { // input ')', change left and right 36 flag = true; 37 continue; 38 } 39 if (input[i] == '(') { 40 i++; // for each first variable 41 if (input[i] == '-') { 42 sign = true; // '-' is near the '(' 43 i++; 44 } 45 else { 46 sign = false; // means that '+' 47 } 48 } 49 else if (i == 0 || i == (input.length() - 1)) { // if left or right is single variable 50 single_left = true; 51 sign = false; // it is positive '+' 52 } 53 else { 54 if (input[i] == '-') 55 sign = true; 56 else 57 sign = false; 58 i++; 59 } 60 // input data 61 push_data.second = input[i]; 62 push_data.first = sign ? '-' : '+'; // if sign == true, sign = '-' 63 if(flag) { // push right 64 right->push(push_data); 65 } 66 else { 67 left->push(push_data); 68 } 69 flag = flag | single_left; 70 } 71 } 72 void Distribution(pair_char left,const pair_char* right,pair_string *out) { 73 bool flag_left; 74 bool flag_right; // if flag == true, the sign of this variable is '-', else is '+' 75 std::string var_left; // for left variable 76 std::string var_right; //for right variable 77 pair_char copy_right; 78 79 while(!left.empty()){ 80 copy_right = *right; //initialization 81 if(left.front().first == '-'){ 82 flag_left = true; 83 } 84 else{ 85 flag_left = false; 86 } 87 var_left = left.front().second; 88 left.pop(); 89 while(!copy_right.empty()){ 90 if(copy_right.front().first == '-'){ 91 flag_right = true; 92 } 93 else{ 94 flag_right = false; 95 } 96 var_right = copy_right.front().second; 97 copy_right.pop(); 98 if(flag_left ^ flag_right){ // xor is 0 means that '+', else is '-' 99 out->push(std::make_pair('-',var_left + var_right)); 100 } 101 else { 102 out->push(std::make_pair('+',var_left + var_right)); 103 } 104 } 105 } 106 } 107 void print_ans (pair_string out){ 108 char sign = out.front().first; 109 std::string var = out.front().second; 110 out.pop(); 111 if(sign == '-'){ 112 cout << '-'; 113 } 114 cout << var; 115 while(!out.empty()){ 116 sign = out.front().first; 117 var = out.front().second; 118 out.pop(); 119 cout << sign << var; 120 } 121 cout << endl; 122 }
二
输入和输出同上述
注意同一个变量可能会输入多次
保证每一个变量由一个字母(包括大小写)组成
输出规则:
1. 对子内部的顺序由每个变量的输入顺序排序。假如b比a先输入过,即使a在被乘数中,a与b如果成对的话对子应该为 ba
2. 如果一个对子是两个相同变量成对,应该输出其次方形式,例如a*a的情况,则应该输出为 a^2 而不是aa
3. 不同对子顺序应该先由对子内左边的变量输入顺序排序,相同左边的变量之间再由右边的变量输入顺序排序。
如果为平方,则视为左边右边的变量都为该变量,例如a^2中,视为其左边与右边的变量都为a
4. 如果不同对子之间由相同两个变量成对,应该进行正常数学加减,数字与对子之间没有相隔,例如ab+ab+ab = 3ab。若数字为0则不输出该对子
5. 如果第一个对子是正数,则不需要输出'+';如果为负数则应该输出'-'
样例1:
输入
a(a+b+c)
输出
a^2+ab+ac
Hint:变量输入顺序为a b c
样例2:
输入
(a+b+c)a
输出
a^2+ab+ac
Hint:变量输入顺序为a b c
样例3:
输入
(a+b-c)(b-c+d)
输出
ab-ac+ad+b^2-2bc+bd+c^2-cd
Hint:变量输入顺序为a b c d
样例4:
输入
(b-c+d)(a+b-c)
输出
b^2-2bc+bd+ba+c^2-cd-ca+da
Hint:变量输入顺序为b c d a
样例5:
输入
aa
输出
a^2
思路:( 笔者直接将此题跳过了,因此此思路写的比较草率,建议看下面多个乘数的思路)
维护两个队列,分别是被乘数、乘数
维护一个小根堆,为积,排序的价值是内部变量的输入顺序(从1开始),用来给对子之间进行排序。
被乘数、乘数队列的数据为两个字符,分别代表正负符号和变量名
积的小根堆数据为一个字符和一个小根堆,小根堆用来给对子内部变量排序,价值是变量的输入顺序(从1开始)。
用内嵌循环来分配。
用专门变量分别记录 对子之间、对子内部的相同变量个数,当下一个的对子/变量不一样的时候就输出;有一个细节点就是如果为空,则强行输出。
代码略,下方代码能处理本体。
三
输入:
一个乘法,乘法由多个加减法组成。(上述两题都是两个)
(如果此题输入的加减法是两个,则与第二题完全一样)
输出同一、二
输出规则:
1. 对子内部的顺序由每个变量的输入顺序排序
2 若有多个相同变量成对,则应该展示其幂形式,例如 aaabbc则应该输出为 a^3b^2c
3.如果不同对子之间由相同两个变量成对,应该进行正常数学加减,数字与对子之间没有隔开,例如ab+ab+ab = 3ab。若数字为0则不输出该对子
4. 对子之间输出顺序:
设最左边的变量(不包括数字)为第一个变量,其右边的为第二个变量,以此类推;
如果变量中有次方,则应该根据次方规定其第n个变量,例如a^3b^2c中,第1~3个变量为a,第4~5个变量为b,第6个变量为c
先由第一个变量的输入顺序排序,第一个变量相同则由第二个变量输入顺序排序,以此类推;
5. 如果第一个对子是正数,则不需要输出'+';如果为负数则应该输出'-'
样例1:
输入
(a+b-c)(b-c+d)
输出
ab-ac+ad+b^2-2bc+bd+c^2-cd
样例2:
输入
(a+b-c)a(b-c+d)
输出
a^2b-a^2c+a^2d+ab^2-2abc+abd+ac^2-acd
思路:
一个变量包含其变量名、符号(即下述代码的 variable)
维护一个队列,用来储存单个加减法内部的所有变量 (即下述代码的 queue<variable>)
维护一个队列,用来储存各个加减法(即下述代码的 input_que = queue<queue<variable> >)(实际上也可以vector)
维护一个小根堆,用来储存单个对子内部的变量,价值为各个变量的输入顺序 (下述代码的heap_var = priority_queue<variable>)
结构体data包含heap_var和一个char sign,sign表示整个heap_var最终得到的符号,整体异或得到
维护一个小根堆,储存data,用来表示不同对子之间的顺序,价值为每个对子的价值(下述代码的heap_data = priority_queue<data>)
积为heap_data
因为输入固定(是大小写字母,共48个)输入顺序价值用一个int数组表示,其中0~23为小写字母(ch - 'a'),24~47为大写字母(ch - 'A' + 24),从1开始记录(如果为0说明没记录过)。
如果输入不固定(例如字符串),可以用map来表示价值。
输入维护一个栈,表示括号。如果输入的为变量且栈为空,则当成单独一个变量作为队列压入 input_que
乘法分配类似于排列组合,用递归枚举即可1
最终输出检测对子内部、对子之间的相同个数(在data、variable分别写一个“==”的operator)
对子之间的个数要注意:如果大于2或者小于-2,就输出数字;如果为1就不输出数字(但是要注意是否输出符号);如果为0就不输出;如果为负数可以直接输出数字不输出负号,但是要特殊处理 -1的情况
代码:
1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <string> 5 6 #define cout std::cout 7 #define cin std::cin 8 #define endl std::endl 9 10 struct variable{ 11 char var; 12 char sign; 13 int value; 14 bool operator < (const variable p) const { 15 return this->value > p.value; // small root heap 16 } 17 bool operator == (const variable p) const { 18 return this->var == p.var; 19 } 20 }; 21 typedef std::priority_queue<variable> heap_var; 22 struct data { 23 heap_var que_var; 24 char sign; 25 data() : que_var(heap_var{}), sign('-'){} 26 // ensure this->size == p.size 27 bool operator < (const data &p) const { // small root heap same as "variable" 28 heap_var left = this->que_var; 29 heap_var right = p.que_var; 30 while(!left.empty()) { 31 if(left.top() == right.top()) { // top equal 32 left.pop(); 33 right.pop(); 34 } 35 else { 36 return left.top() < right.top(); // not equal, small root 37 } 38 } 39 return left.top() < right.top(); // all equal 40 } 41 bool operator == (const data &p) const { 42 if (this->que_var.size() != p.que_var.size()) 43 return false; 44 heap_var left = this->que_var; 45 heap_var right = p.que_var; 46 while(!left.empty()) { 47 if(left.top() == right.top()) { // top equal 48 left.pop(); 49 right.pop(); 50 } 51 else { 52 return false; // not equal 53 } 54 } 55 return true; // all equal 56 } 57 void calc_sign() { 58 bool flag_sign_final = false; // flag_sign == 1 means that sign == '-' 59 heap_var copy_var = this->que_var; 60 while(!copy_var.empty()){ 61 bool flag_sign_heap = (copy_var.top().sign == '-') ? true:false; 62 flag_sign_final ^= flag_sign_heap; 63 copy_var.pop(); 64 } 65 this->sign = flag_sign_final? '-':'+'; 66 } 67 }; 68 typedef std::queue<std::queue<variable> > input_que; // queue for queue of variable 69 typedef std::priority_queue<data> heap_data; 70 71 int var_value[48] = {0}; // for 0~23: value of 'a'~'z'; 24 ~ 47: value of 'A'~'Z" 72 73 void read_queue(input_que *que); 74 void Distribution(input_que,data,heap_data*); 75 void print_heapdata(heap_data); 76 77 int main() { 78 input_que que; 79 heap_data ans; 80 81 read_queue(&que); 82 Distribution(que,data(),&ans); 83 print_heapdata(ans); 84 return 0; 85 } 86 87 void read_queue(input_que *que) { 88 std::string input; 89 std::stack<char> flag; // for brackets 90 std::queue<variable> que_var; // for each queue variable 91 variable var = {}; // for each input variable 92 bool sign = false; // for sign == true, means this variable is negative; false means is positive 93 int input_value = 1; // for value of variable while input 94 95 cin >> input; 96 for(int i = 0;i < input.length();i++){ 97 if(input[i] == '(') 98 flag.push(input[i]); 99 else if(input[i] == ')'){ 100 flag.pop(); 101 que->push(que_var); // push to queue for queue of variable 102 while(!que_var.empty()) // clear queue of variable 103 que_var.pop(); 104 } 105 else if(input[i] == '+') 106 sign = false; 107 else if(input[i] == '-') 108 sign = true; 109 else { // else means that input is variable 110 int num; 111 if(input[i] >= 'a' && input[i] <= 'z') 112 num = input[i] - 'a'; 113 else 114 num = input[i] - 'A' + 24; 115 if(var_value[num] == 0) // if never input this variable 116 var_value[num] = input_value++; 117 118 // initialization fot this variable 119 var.var = input[i]; 120 var.value = var_value[num]; 121 var.sign = sign ? '-':'+'; // true->'-'; false->'+' 122 que_var.push(var); 123 if(flag.empty()){ // for single variable, exit now queue of variable 124 que->push(que_var); 125 que_var.pop(); 126 } 127 sign = false; // initialization for each variable to '+' 128 } 129 } 130 } 131 void Distribution(input_que que,data Data,heap_data* heapData) { // Recursive traversal queue for queue of variable 132 if(que.empty()) { // leaf, data pushed into heapData 133 Data.calc_sign(); // calculate sign 134 heapData->push(Data); 135 return; 136 } 137 std::queue<variable> que_var = que.front(); 138 que.pop(); 139 while(!que_var.empty()){ 140 variable var = que_var.front(); 141 data copy_Data = Data; // flash back 142 copy_Data.que_var.push(var); 143 Distribution(que,copy_Data,heapData); 144 que_var.pop(); 145 } 146 } 147 void print_heapdata(heap_data heapData){ 148 bool firstdata = false; // for fist input 149 150 data next_data; 151 data this_data; 152 int num_data = 0; 153 while(!heapData.empty()){ 154 this_data = heapData.top(); 155 heapData.pop(); 156 if(!heapData.empty()) 157 next_data = heapData.top(); 158 else 159 next_data = data(); // if empty, not same data 160 161 // calculate the number of same data 162 if(this_data.sign == '+') 163 num_data++; 164 else 165 num_data--; 166 167 // same data, continue 168 if (next_data == this_data) { 169 continue; 170 } 171 // 0, not print 172 if (num_data == 0) { 173 num_data = 0; 174 continue; 175 } 176 177 // print sign 178 if (firstdata && num_data > 0){ 179 cout << '+'; 180 } 181 else if(num_data == -1) { 182 cout << '-'; 183 } 184 else{ 185 firstdata = true; 186 } 187 // print number of data 188 if(num_data >= 2 || num_data <= -2) 189 cout << num_data; 190 num_data = 0; 191 192 // for print variable 193 char this_var; 194 char next_var; 195 int num_char = 0; 196 while(!this_data.que_var.empty()) { 197 this_var = this_data.que_var.top().var; 198 num_char++; 199 this_data.que_var.pop(); 200 // for next variable 201 if (!this_data.que_var.empty()) 202 next_var = this_data.que_var.top().var; 203 else 204 next_var = '0'; // if empty, print. 205 // print 206 if (next_var != this_var) { 207 cout << this_var; 208 if(num_char >= 2) { // print '^' 209 cout << '^' << num_char; 210 } 211 num_char = 0; 212 } 213 } 214 } 215 }