目的
用来处理多项式公式:对于一个仅含有自变量x的多项式,将其按次数展开。
大致思路
一、拆括号
二、读取每个无括号的表达式
三、记录结果
四、以后再遇到这个括号直接读取结果
具体内容在实现过程中,以下顺序是按照我们一开始的思考顺序,又简入深
poly
struct poly{
int dag;
int pre_op;//多项式前面的符号 1234代表 +*/^
pair<int,int>c[N];//c[a]分数表达c^a的系数
int pre,aft;//指针 前后的多项式
int id;//当前多项式编号
void clear(){
memset(c,0,sizeof(c));
dag=0;
}
int step;//记录位于的括号层数
};
我们最终要把整个表达式变成一个多项式,因此我以多项式为一个单元
具体内容之后遇见会说到
basic_work
里面放着所有不加括号的运算内容
包括数字的加、乘、除、乘方
实现过程
0.字符串转表达式
字符串转表达式要对数字、运算符、括号分别处理,思维要非常细致,有很多情况。
因此我采用数字与符号分开处理的方式
1.无括号多项式运算
我们发现,对于一个式子 a + b − c ∗ d / e f a+b-c*d/e^f a+b−c∗d/ef,如果我们把数字先提取出来放到一个 r e c − n u m rec-num rec−num数组中,然后每次遇到一个运算符,就可以知道对应的数字的多少。
然后我们一开始以一个数字以及前面的运算符为一个单元,也就是一个poly。压入vector中,等待之后的合并操作。
p r e − o p pre-op pre−op 1 2 3 4分别代表 + * / ^
1.0数字四则运算
由于有/,电脑中不可能记录一个无限小数,因此所有数字都采用了分数的形式去记录。
p a i r < x , y > pair<x,y> pair<x,y>
它的相关运算即分数运算,每次除以gcd(辗转相除得到)以保证是既约分数。
int gcd(int x,int y){
if(x<y)swap(x,y);
if(y==0)return x;
return gcd(y,x%y);
}
pair<int,int> num_plus(pair<int,int> a,pair<int,int> b){
pair<int,int>ans;
if(a.first==0)return b;
if(b.first==0)return a;
ans.first=a.first*b.second+a.second*b.first;
ans.second=a.second*b.second;
int g=gcd(abs(ans.first),abs(ans.second));
ans.first/=g,ans.second/=g;
return ans;
}
pair<int,int> num_multi(pair<int,int>a,pair<int,int>b){
pair<int,int>ans;
ans.first=0;
if(a.first==0||b.first==0)return ans;
ans.first=a.first*b.first;
ans.second=a.second*b.second;
int g=gcd(abs(ans.first),abs(ans.second));
ans.first/=g,ans.second/=g;
return ans;
}
1.1加减
两个多项式按照次数相加。
poly plus(poly a,poly b){//多项式 a+b 各个系数依次相加
for(int i=0;i<N;i++){
a.c[i]=num_plus(a.c[i],b.c[i]);
}
return a;
}
1.2乘除
将一个多项式中按照次数排序的每一项依次去乘另一个多项式。
poly multi(poly a,poly b){//枚举b的每次 然后多项式乘单项式 把每次结果加到ans上
poly ans=a;
ans.clear();//预处理数组 不改变标签、前后标记
for(int i=0;i<N;i++){
if(b.c[i].first==0)continue;
for(int j=0;j<N;j++){
if(a.c[j].first==0)continue;
ans.c[i+j]=num_plus(ans.c[i+j],num_multi(a.c[j],b.c[i]));
}
}
return ans;
}
poly div(poly a,pair<int,int>b){//只能除以一个分数
for(int i=0;i<N;i++){
if(a.c[i].first==0)continue;
a.c[i]=num_multi(a.c[i],make_pair(b.second,b.first));
}
return a;
}
1.3乘方
乘方其实是多个乘法的叠加,乘方运算采用二进制优化的快速幂。
poly qpow(poly a,int b){
if(b<0){
for(int i=0;i<N;i++){
swap(a.c[i].first,a.c[i].second);
}
b=-b;
}
poly zero=a;
zero.clear();
zero.c[0]=make_pair(1,1);
if(b==0)return zero;
poly ans=qpow(a,b>>1);
if(b&1)return multi(multi(ans,ans),a);
return multi(ans,ans);
}
2.多项式合并处理
现在每个多项式都会合并了,问题变成了如何去合并。
首先要有一定顺序,按照运算优先级合并。
其次要保证vector内部的元素有序。因为两个多项式合并之后,会有一个就没用了,但它依然在vector中,这就需要我们手写指针来记录每个多项式在经历若干次合并之后前后对应多项式都是什么。
也就是poly里面的这些
int pre,aft;//指针 前后的多项式
int id;//当前多项式编号
下面以合并乘方运算为例,加减乘除都大同小异
void work_pow(){
for(int i=v.size()-1;i>=0;i--){//因为 a^b^c是从上到下 所以要从后往前遍历
if(v[i].dag)continue;
if(v[i].pre_op==4){
int pre_pre=v[v[i].pre].pre;
int pre_aft=v[v[i].pre].aft;
int aft_pre=v[i].pre;
int aft_aft=v[i].aft;
poly x=qpow(v[aft_pre],v[i].c[0].first);
x.pre=pre_pre;
x.aft=pre_aft;
//下面开始调整v[i]的所有箭头
if(aft_aft<v.size())v[aft_aft].pre=aft_pre;
x.aft=aft_aft;
v[i].dag=1;
//调整结束 i已经废弃了 打标记
v[aft_pre]=x;
}
}
}
3.括号处理
第一个问题是找到匹配的括号。
我们用一个栈:stack,每次遇见(就把它的位置压入stack,然后遇见)就把栈顶元素弹出,那个就是匹配的括号。
然后我们就找到了一个有括号的式子,它里面要么是无括号的,要么是有括号并且已经处理好了的。
现在就需要在字符串转表达式中加一些东西。如果遇到了(,直接跳到下一个)去记录数字,中间的直接读取之前的处理结果,然后把那个poly压入vector,这个vector是每次调用basic_work的时侯都要初始化的。
于是我们还需要一个vector,去记录整个表达式的处理情况。
括号处理操作
vector<poly>v1;//有括号的总序列
struct bracket_work{
poly bracket_exchange(char *s){//按照括号分级处理
//思路 遍历s
//每搜索到一个左括号 把字符位置压入栈
//每搜索到一个右括号 栈顶左括号为匹配括号
//把这部分字符串送给basic进行求解
//法一:然后在basic里面 遇到)无视
//遇到(肯定是已经处理好的 把对应的poly放进去就好了
stack<int>st;//记录左括号在s的位置
int len=strlen(s);
for(int i=0;i<len;i++){
if(s[i]=='('){
st.push(i);
}
else if(s[i]==')'){
char use[N];
memset(use,0,sizeof(use));
int from=st.top();
st.pop();
to[from]=i;
for(int j=from+1;j<i;j++){
use[j-from-1]=s[j];
}
poly rec=p.go(from+1,use);
if(s[from-1]==')'||(s[from-1]>='0'&&s[from-1]<='9'))rec.pre_op=2;
mp[from]=rec;
}
}
return mp[0];
}
}b;
4.输出print
按照次数升序顺序依次输出即可。
void print(poly x){
if(x.dag)return;
for(int i=0;i<N;i++){
if(x.c[i].first==0)continue;
if(x.pre_op==1){
x.c[i].first>0?cout<<"+":cout<<"-";
}
else if(x.pre_op==2)cout<<"*";
else if(x.pre_op==3)cout<<"/";
else if(x.pre_op==4)cout<<"^";
if(x.c[i].second!=1)cout<<abs(x.c[i].first)<<"/"<<x.c[i].second<<"x^"<<i;
else cout<<abs(x.c[i].first)<<"x^"<<i;
}
cout<<endl;
}
总体代码
下附整体代码
#include<bits/stdc++.h>//括号前直接数字没做出来 问题已经标出来了
using namespace std;
const int N=2021;
struct poly{
int dag;
int pre_op;//多项式前面的符号 1234代表 +*/^
pair<int,int>c[N];//c[a]分数表达c^a的系数
int pre,aft;//指针 前后的多项式
int id;//当前多项式编号
void clear(){
memset(c,0,sizeof(c));
dag=0;
}
};
operator == (poly x,poly y){
bool flag=1;
for(int i=0;i<N;i++){
if(x.c[i].first==y.c[i].first&&x.c[i].second==y.c[i].second)continue;
flag=0;
}
return flag;
}
vector<poly>v;//多次处理无括号
map<int,poly>mp;//是(的字符位 直接对应相应的poly
map<int,int>to;//原数组中每个(对应的)
struct basic_poly_work{//处理无括号的 多次使用
int top;//记录最高括号级数
poly exchange(int k,char *s){//字符串转化为多项式 k代表数组后移几位
//思路:先把所有数字记录下来 然后根据符号一个一个填数字
v.clear();//有括号 需要多次调用 这句话特别重要
int len=strlen(s);
int rec_num[N];//记录数字 之后一个一个填入符号的空中
int rec_id[N];//记录每个数字对应的位置 以最后一位数字为准
int sz=0;//rec数组的大小
int rec=0;
bool flag=0;
for(int i=0;i<len;i++){//处理数字
if(s[i]>='0'&&s[i]<='9'){
rec*=10;
rec+=s[i]-'0';
flag=1;
}
else if(flag){
rec_id[sz]=i;
rec_num[sz++]=rec;
rec=0;
flag=0;
}
if(s[i]=='('){
i=to[i+k]-k;
flag=0;
}
}
if(flag){
rec_num[sz]=rec;
rec_id[sz++]=len-1;
rec=0;
}
int id=0;//rec_num数组指针
for(int i=0;i<len;i++){//把数字填入符号
if(i==0||s[i]>'9'||s[i]<'0'){
poly x;
x.clear();
if(s[i]==')')continue;
if(s[i]=='('){//之前如果是数字 要添加乘号
x=mp[i+k];
if(i==0){
x.pre_op=1;
}
else if(s[i-1]=='+'||s[i-1]=='-'){
x.pre_op=1;
if(s[i-1]=='-'){
for(int i=0;i<N;i++){
x.c[i].first=-x.c[i].first;
}
print(x);
}
}
else if(s[i-1]=='*'||(s[i-1]>='0'&&s[i-1]<='9')){
x.pre_op=2;
if(s[i-1]!='*'){
poly new_num,xxx;
new_num.clear(),xxx.clear();
new_num.c[0]=make_pair(rec_num[id++],1);
if(new_num==xxx)continue;
v.push_back(new_num);
}
}
else if(s[i-1]=='x'||s[i-1]==')')x.pre_op=2;
else if(s[i-1]=='/')x.pre_op=3;
else if(s[i-1]=='^')x.pre_op=4;
v.push_back(x);
//开始移动i和id
i=to[i+k]-k;
continue;
}
if(s[i]>='0'&&s[i]<='9'){//一定i==0
x.pre_op=1;
x.c[0]=make_pair(rec_num[id++],1);
}
else if(s[i]=='+'||(i==0&&s[i]!='-')){
if(i==0&&s[i]=='x'){
x.c[1]=make_pair(1,1);
}
else if(s[i+1]=='x'){
x.c[0]=make_pair(1,1);
}
else if(s[i+1]=='('||s[i+1]==')')continue;
else{
x.c[0]=make_pair(rec_num[id++],1);
}
x.pre_op=1;
}
else if(s[i]=='-'){
if(s[i+1]=='x'){
x.c[0]=make_pair(-1,1);
}
else if(s[i+1]=='('||s[i+1]==')'){
continue;
}
else{
x.c[0]=make_pair(-rec_num[id++],1);
}
x.pre_op=1;
}
else if(s[i]=='*'){
if(s[i+1]=='x'){
x.c[0]=make_pair(1,1);
}
else if(s[i+1]=='('||s[i+1]==')')continue;
else{
x.c[0]=make_pair(rec_num[id++],1);
}
x.pre_op=2;
}
else if(s[i]=='/'){
x.pre_op=3;
if(s[i+1]=='('||s[i+1]==')')continue;
x.c[0]=make_pair(rec_num[id++],1);
}
else if(s[i]=='^'){
x.pre_op=4;
if(s[i+1]=='('||s[i+1]==')')continue;
x.c[0]=make_pair(rec_num[id++],1);
}
else if(s[i]=='x'){
x.pre_op=2;
x.c[1]=make_pair(1,1);
}
v.push_back(x);
}
}
for(int i=0;i<v.size();i++){//处理pre aft编号
v[i].pre=i-1;
v[i].aft=i+1;
}
}
void print(poly x){
if(x.dag)return;
for(int i=0;i<N;i++){
if(x.c[i].first==0)continue;
if(x.pre_op==1){
x.c[i].first>0?cout<<"+":cout<<"-";
}
else if(x.pre_op==2)cout<<"*";
else if(x.pre_op==3)cout<<"/";
else if(x.pre_op==4)cout<<"^";
if(x.c[i].second!=1)cout<<abs(x.c[i].first)<<"/"<<x.c[i].second<<"x^"<<i;
else cout<<abs(x.c[i].first)<<"x^"<<i;
}
cout<<endl;
}
int gcd(int x,int y){
if(x<y)swap(x,y);
if(y==0)return x;
return gcd(y,x%y);
}
pair<int,int> num_plus(pair<int,int> a,pair<int,int> b){
pair<int,int>ans;
if(a.first==0)return b;
if(b.first==0)return a;
ans.first=a.first*b.second+a.second*b.first;
ans.second=a.second*b.second;
int g=gcd(abs(ans.first),abs(ans.second));
ans.first/=g,ans.second/=g;
return ans;
}
pair<int,int> num_multi(pair<int,int>a,pair<int,int>b){
pair<int,int>ans;
ans.first=0;
if(a.first==0||b.first==0)return ans;
ans.first=a.first*b.first;
ans.second=a.second*b.second;
int g=gcd(abs(ans.first),abs(ans.second));
ans.first/=g,ans.second/=g;
return ans;
}
poly plus(poly a,poly b){//多项式 a+b 各个系数依次相加
for(int i=0;i<N;i++){
a.c[i]=num_plus(a.c[i],b.c[i]);
}
return a;
}
poly multi(poly a,poly b){//枚举b的每次 然后多项式乘单项式 把每次结果加到ans上
poly ans=a;
ans.clear();//预处理数组 不改变标签、前后标记
for(int i=0;i<N;i++){
if(b.c[i].first==0)continue;
for(int j=0;j<N;j++){
if(a.c[j].first==0)continue;
ans.c[i+j]=num_plus(ans.c[i+j],num_multi(a.c[j],b.c[i]));
}
}
return ans;
}
poly div(poly a,pair<int,int>b){//只能除以一个分数
for(int i=0;i<N;i++){
if(a.c[i].first==0)continue;
a.c[i]=num_multi(a.c[i],make_pair(b.second,b.first));
}
return a;
}
poly qpow(poly a,int b){
if(b<0){
for(int i=0;i<N;i++){
swap(a.c[i].first,a.c[i].second);
}
b=-b;
}
poly zero=a;
zero.clear();
zero.c[0]=make_pair(1,1);
if(b==0)return zero;
poly ans=qpow(a,b>>1);
if(b&1)return multi(multi(ans,ans),a);
return multi(ans,ans);
}
void work_pow(){
for(int i=v.size()-1;i>=0;i--){//因为 a^b^c是从上到下 所以要从后往前遍历
if(v[i].dag)continue;
if(v[i].pre_op==4){
int pre_pre=v[v[i].pre].pre;
int pre_aft=v[v[i].pre].aft;
int aft_pre=v[i].pre;
int aft_aft=v[i].aft;
poly x=qpow(v[aft_pre],v[i].c[0].first);
x.pre=pre_pre;
x.aft=pre_aft;
//下面开始调整v[i]的所有箭头
if(aft_aft<v.size())v[aft_aft].pre=aft_pre;
x.aft=aft_aft;
v[i].dag=1;
//调整结束 i已经废弃了 打标记
v[aft_pre]=x;
}
}
}
void work_multi(){//处理乘法 除法
for(int i=0;i<v.size();i++){
if(v[i].dag)continue;
if(v[i].pre_op==2){
int pre_pre=v[v[i].pre].pre;
int pre_aft=v[v[i].pre].aft;
int aft_pre=v[i].pre;
int aft_aft=v[i].aft;
poly x=multi(v[aft_pre],v[i]);
x.pre=pre_pre;
x.aft=pre_aft;
//下面开始调整v[i]的所有箭头
if(aft_aft<v.size())v[aft_aft].pre=aft_pre;
x.aft=aft_aft;
v[i].dag=1;
//调整结束 i已经废弃了 打标记
v[aft_pre]=x;
}
else if(v[i].pre_op==3){
int pre_pre=v[v[i].pre].pre;
int pre_aft=v[v[i].pre].aft;
int aft_pre=v[i].pre;
int aft_aft=v[i].aft;
poly x=div(v[aft_pre],v[i].c[0]);
x.pre=pre_pre;
x.aft=pre_aft;
if(aft_aft<v.size())v[aft_aft].pre=aft_pre;
x.aft=aft_aft;
v[i].dag=1;
v[aft_pre]=x;
}
}
}
poly work_plus(){//处理加法
for(int i=0;i<v.size();i++){
if(v[i].dag)continue;
if(v[i].pre_op==1&&i!=0){
int pre_pre=v[v[i].pre].pre;
int pre_aft=v[v[i].pre].aft;
int aft_pre=v[i].pre;
int aft_aft=v[i].aft;
poly x=plus(v[aft_pre],v[i]);
x.pre=pre_pre;
x.aft=pre_aft;
if(aft_aft<v.size())v[aft_aft].pre=aft_pre;
x.aft=aft_aft;
v[i].dag=1;
v[aft_pre]=x;
}
}
return v[0];
}
poly go(int k,char *s){
exchange(k,s);
work_pow();
work_multi();
return work_plus();
}
}p;
vector<poly>v1;//有括号的总序列
struct bracket_work{
poly bracket_exchange(char *s){//按照括号分级处理
//思路 遍历s
//每搜索到一个左括号 把字符位置压入栈
//每搜索到一个右括号 栈顶左括号为匹配括号
//把这部分字符串送给basic进行求解
//法一:然后在basic里面 遇到)无视
//遇到(肯定是已经处理好的 把对应的poly放进去就好了
stack<int>st;//记录左括号在s的位置
int len=strlen(s);
for(int i=0;i<len;i++){
if(s[i]=='('){
st.push(i);
}
else if(s[i]==')'){
char use[N];
memset(use,0,sizeof(use));
int from=st.top();
st.pop();
to[from]=i;
for(int j=from+1;j<i;j++){
use[j-from-1]=s[j];
}
poly rec=p.go(from+1,use);
if(s[from-1]==')'||(s[from-1]>='0'&&s[from-1]<='9'))rec.pre_op=2;
mp[from]=rec;
}
}
return mp[0];
}
}b;
int main(){
char s[N];
cin>>s+1;
s[0]='(';//新加结束标记
s[strlen(s)]=')';
for(int i=0;i<strlen(s);i++){
if(s[i]>='0'&&s[i]<='9'&&s[i+1]=='('){
for(int j=strlen(s);j>i;j--){
s[j]=s[j-1];
}
s[i+1]='*';
}
}
cout<<s<<endl;
p.print(b.bracket_exchange(s));
}