【解题报告】POJ-1467 Symbolic Derivation
原题地址:http://poj.org/problem?id=1467
题目大意:
对一个式子求导,给的式子包括常量,字母x,+,-,*,/,ln()运算符,任意嵌套的括号。求的导数式子不用化简,如1*x这样的式子不用变成x。下面给出了一些求导规则和运算优先级:
1.乘除的优先级大于加减。
2.同优先级结合性从左往右。
3. 求导规则:
(a + b)' = a' + b'
(a - b)' = a' - b'
(a * b)' = (a' * b + a * b')
(a / b)' = (a' * b - a * b') / b^2 Note: 写 b^2 而不是 (b*b)
ln(a)' = (a')/(a)
x' = 1
常数的导数 = 0
要注意的是,如上所给的规则中,有括号的部分要在求导式子中相应的加上括号。如:
输入1*1
输出(0*1+1*0)
这里的括号不能去掉。
解题思路:
将整个式子当做一个字符串来处理。
如果这个字符串是一个数字,则求导结果是 0
如果这个字符串是一个x,则求导结果是 1
否则,找到最后计算的那一个运算符(这个字符不能在任何括号里),如:" (2*ln(x+1.7)-x*x)/((-7)+3.2*x*x)+(x+3*x)*x "中,先最后计算的运算符是红色的加号。然后以这个加号为分界点,将整个式子分解成两部分,“ (2*ln(x+1.7)-x*x)/((-7)+3.2*x*x) ” 和“(x+3*x)*x” 然后根据加法求导法则,分别求两部分的导数,则将两部分分别递归一遍。
若没有找到上一条所述的运算符(即整个字符串包含在括号里,或者为ln运算)
如果是整个括号包含的字符串,则去掉这个括号得到的字符串递归一遍。
如果是ln()运算符,则根据ln()求导法则递归。
解题代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<stack> 5 using namespace std; 6 class String 7 { 8 public: 9 char s[105]; 10 String(){s[0]=0;} 11 String(String& s1){strcpy(s,s1.s);} 12 bool isnum(); 13 }; 14 char ans[105]; 15 ostream& operator<<(ostream& out,String &s1) 16 { 17 cout<<s1.s; 18 return out; 19 } 20 bool String::isnum() 21 { 22 int i=0; 23 if(s[0]=='-') i++; 24 for(;s[i];i++) 25 { 26 if(s[i]=='.'||(s[i]>='0'&&s[i]<='9')) ; 27 else break; 28 } 29 if(!s[i]) return true; 30 else return false; 31 } 32 void qiudao(String s1); 33 void jia(String s1,String s2) 34 { 35 qiudao(s1); 36 strcat(ans,"+"); 37 qiudao(s2); 38 } 39 void jian(String s1,String s2) 40 { 41 qiudao(s1); 42 strcat(ans,"-"); 43 qiudao(s2); 44 } 45 void cheng(String s1,String s2) 46 { 47 strcat(ans,"("); 48 qiudao(s1); 49 strcat(ans,"*"); 50 strcat(ans,s2.s); 51 strcat(ans,"+"); 52 strcat(ans,s1.s); 53 strcat(ans,"*"); 54 qiudao(s2); 55 strcat(ans,")"); 56 } 57 void chu(String s1,String s2) 58 { 59 strcat(ans,"("); 60 qiudao(s1); 61 strcat(ans,"*"); 62 strcat(ans,s2.s); 63 strcat(ans,"-"); 64 strcat(ans,s1.s); 65 strcat(ans,"*"); 66 qiudao(s2); 67 strcat(ans,")/"); 68 strcat(ans,s2.s); 69 strcat(ans,"^2"); 70 } 71 void ln(String s1) 72 { 73 strcat(ans,"("); 74 qiudao(s1); 75 strcat(ans,")/("); 76 strcat(ans,s1.s); 77 strcat(ans,")"); 78 } 79 void qiudao(String s1) 80 { 81 int i; 82 if(s1.isnum()) {strcat(ans,"0");return ;}//如果字符串表示一个数字,则求导结果为 0 83 if(strcmp(s1.s,"x")==0) {strcat(ans,"1");return ;}//如果字符串是一个x,则求导结果为 1 84 int len=strlen(s1.s); 85 //下面用于计算优先级最低的一个运算符。 86 int n=-1,you=3; 87 for(i=0;s1.s[i];i++) 88 { 89 if(i!=0&&((s1.s[i]=='+'||s1.s[i]=='-')&&you>=1)) {n=i;you=1;break;} 90 if(i!=0&&((s1.s[i]=='*'||s1.s[i]=='/')&&you>=2)) {n=i;you=2;} 91 if(s1.s[i]=='(') 92 { 93 int n=1; 94 while(n) 95 { 96 i++; 97 if(s1.s[i]=='(')n++; 98 if(s1.s[i]==')')n--; 99 } 100 } 101 } 102 if(you!=3) 103 { 104 String ss1,ss2; 105 strncpy(ss1.s,s1.s,n); 106 ss1.s[n]=0; 107 strncpy(ss2.s,&s1.s[n+1],len-n-1); 108 ss2.s[len-n-1]=0; 109 switch(s1.s[n]) 110 { 111 case '+':jia(ss1,ss2);break; 112 case '-':jian(ss1,ss2);break; 113 case '*':cheng(ss1,ss2);break; 114 case '/':chu(ss1,ss2);break; 115 } 116 return ; 117 } 118 if(s1.s[0]=='('&&s1.s[len-1]==')') 119 { 120 String s2; 121 strncpy(s2.s,s1.s+1,len-2); 122 s2.s[len-2]=0; 123 strcat(ans,"("); 124 qiudao(s2); 125 strcat(ans,")"); 126 return ; 127 } 128 if(strncmp(s1.s,"ln(",3)==0&&s1.s[len-1]==')') 129 { 130 String ss1; 131 strncpy(ss1.s,s1.s+3,len-4); 132 ss1.s[len-4]=0; 133 ln(ss1); 134 } 135 } 136 int main() 137 { 138 String s1; 139 int i; 140 while(cin>>s1.s) 141 { 142 ans[0]=0; 143 qiudao(s1); 144 for(i=0;ans[i];i++) 145 { 146 if(ans[i+1]=='-') 147 { 148 if(ans[i]=='+') {cout<<'-';i++;continue;} 149 if(ans[i]=='-') {cout<<'+';i++;continue;} 150 } 151 cout<<ans[i]; 152 } 153 cout<<endl; 154 } 155 return 0; 156 }