[数据结构][应用] 队列的应用 乘法分配律

以下“输入顺序排序”都为先输入的先输出

输入:

一个乘法,乘法由两个加减法组成,两个加减法之间由括号相隔、或者没有相隔
保证每一个变量由一个字母(包括大小写)组成
若一个加减法由两个及以上个变量组成,则用括号括起来,如(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

思路:

维护三个队列,分别是被乘数、乘数、积

被乘数、乘数队列的数据为两个字符,分别代表正负符号和变量名

积的队列数据为一个字符和一个字符串,字符代表正负符号,字符串代表两个变量名相乘

循环被乘数内嵌乘数,积的正负符号等于被乘数与成熟符号的异或,积的字符串等于被乘数与乘数字符串相加

细节点:

  1. 输入要分别处理被乘数(i = 0不为左括号)、乘数(i = queue.length - 1不为右括号)为单个正变量情况
  2. 输入要处理括号内第一个字符是变量还是负号的情况
  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 }

 

 


 

posted @ 2022-11-19 02:37  蒟蒻zExNocs  阅读(135)  评论(0)    收藏  举报