多項式A除以B
這個問題我是在PAT大區賽題裏遇見的。題目如下:
多項式A除以B(25 分)
這仍然是一道關於A/B的題,只不過A和B都換成了多項式。你需要計算兩個多項式相除的商Q和余R,其中R的階數必須小於B的階數。
輸入格式:
輸入分兩行,每行給出一個非零多項式,先給出A,再給出B。每行的格式如下:
N e[1] c[1] ... e[N] c[N]
其中N
是該多項式非零項的個數,e[i]
是第i
個非零項的指數,c[i]
是第i
個非零項的系數。各項按照指數遞減的順序給出,保證所有指數是各不相同的非負整數,所有系數是非零整數,所有整數在整型範圍內。
輸出格式:
分兩行先後輸出商和余,輸出格式與輸入格式相同,輸出的系數保留小數點後1位。同行數字間以1個空格分隔,行首尾不得有多余空格。註意:零多項式是一個特殊多項式,對應輸出為0 0 0.0
-1/27
,但因其舍入後為0.0,故不輸出。
輸入樣例:
4 4 1 2 -3 1 -1 0 -1
3 2 3 1 -2 0 1
輸出樣例:
3 2 0.3 1 0.2 0 -1.0 1 1 -3.1
題目的意思很明確,就是要求 anxn+an-1xn-1+
an-2xn-2
+。。。
+
a1x1
+
a0x0 除以
amxm+
am-1xm-1+
am-2xm-2
+。。。
+
a1x1
+
a0x0 的商和余數。這可以類比多項式除法進行。
這題的樣例數據可表示為:x4-3x2-x-1 除以 3x2-2x+1 求其的商和余數。
手工計算步驟就是下圖所示:
依次乘一個(1/3)x2,(2/9)x,(-26/27),很明顯就是想辦法消掉最高次項,知道所剩的余項最高次小於除數的最高次。
分數化簡後就為答案。(上方為商,下方為余數)。
算法核心部分上面已經講了,接下來講一下數據結構的設置。
因為每一項都是指數、系數這兩個變量,所以我們可以用STL中的map來存儲這一個<指數,系數>鍵值對。
因此我在此設了三個map數組
map<int,double> a; //多項式A(最後的余數) map<int,double> b; //除數 map<int,double> c; //商
多項式A的初始化
1 cin>>lena; //A多項式的項數 2 for(int i=0;i<lena;i++){ 3 int e; 4 double c; 5 cin>e; 6 cin>>c; 7 maxe_a = max(maxe_a,e);//找到A的最高次指數 8 a[e] = a[e] + c; //相同系數即刻合並 9 }
多項式B同理,但要註意多求一個最小項次數。
接下來,最重要的來了,那就是除法運算的過程。首先我們先知道要進行幾次除法的運算。由上面的示例步驟我們可以知道,運算次數為:( A的最高次冪 - B的最高次冪 )+ 1 次,也可理解為( i = max (eA); i >= max(eB); i --)這樣的過程。
商的其中一項就是(當前A的最高次冪系數 / B的最高次冪系數)這是系數,指數為 (當前A的最高次冪 - B的最高次冪),為什麽加一個當前呢?因為A每次最高項都會被(B的最高次項 * 相應商的一項)所消掉,直至A最終變為要求的余數項為止。
余數項,就是A每一項每次被 (B的每項 * 相應項的商)做差後系數沒被削成0的項。
1 for(int i = maxe_a;i>=maxe_b;i--){ 2 if(b[maxe_b]!=0){ 3 div = 1.0*a[i]/b[maxe_b]; 4 //printf("div=%.1lf\n",div); 5 sub = i - maxe_b; 6 c[sub] = div; 7 maxe_c = max(maxe_c,sub); //求商的最高次冪 8 //每次從剩余項的最高次開始,直到B的最低次,每項做差 9 for(int j=i;j>=mine_b;j--){ 10 if(j-sub >= 0){ 11 a[j] = a[j] - b[j-sub]*c[sub]; 12 } 13 } 14 } 15 }
之後c[ ] 就是商,a[ ] 就是余數項。
最後依據題意,為c[ ]數組 a[ ]數組做下四舍五入。接下來講一下怎麽做四舍五入。
因為題目要求保留一位有效數字,所以就先把這個數*10化為(int)+/-0.5,再除以10即可。今後碰見四舍五入問題一次類推!
for(int i=maxe_c;i>=0;i--){ //四舍五入處理 c[i] = (double)((int)(c[i]*10 + (c[i]<0?-0.5:0.5)))/10; if(c[i]){ cnt++; } }
最後奉上此題解的原碼:
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 8 map<int,double> a; 9 map<int,double> b; 10 map<int,double> c; 11 int lena,lenb; 12 13 int main(){ 14 int maxe_a = 0,mine_b=32767,maxe_b=0,maxe_c=0; 15 double div; 16 int sub; 17 cin>>lena; 18 for(int i=0;i<lena;i++){ 19 int e; 20 double c; 21 cin>>e; 22 cin>>c; 23 maxe_a = max(maxe_a,e); //找到A的最高次指數 24 a[e] = a[e] + c; //相同系數即刻合並 25 } 26 cin>>lenb; 27 for(int i=0;i<lenb;i++){ 28 int e; 29 double c; 30 cin>>e; 31 cin>>c; 32 mine_b = min(mine_b,e); //找到B的最低次指數 33 maxe_b = max(maxe_b,e); //找到B的最高次指數 34 b[e] = b[e] + c; //相同系數即刻合並 35 } 36 for(int i = maxe_a;i>=maxe_b;i--){ 37 if(b[maxe_b]!=0){ 38 div = 1.0*a[i]/b[maxe_b]; 39 //printf("div=%.1lf\n",div); 40 sub = i - maxe_b; 41 c[sub] = div; 42 maxe_c = max(maxe_c,sub); //求商的最高次冪 43 for(int j=i;j>=mine_b;j--){ //每次從剩余項的最高次開始,直到B的最低次,每項做差 44 if(j-sub >= 0){ 45 a[j] = a[j] - b[j-sub]*c[sub]; 46 } 47 } 48 } 49 } 50 int cnt=0; 51 for(int i=maxe_c;i>=0;i--){ 52 c[i] = (double)((int)(c[i]*10 + (c[i]<0?-0.5:0.5)))/10;//四舍五入處理 53 if(c[i]){ 54 cnt++; 55 } 56 } 57 if(cnt ==0){ 58 printf("0 0 0.0\n"); 59 }else{ 60 printf("%d",cnt); 61 for(int i=maxe_c;i>=0;i--){ 62 if(c[i]){ 63 printf(" %d %.1lf",i,c[i]); 64 } 65 } 66 printf("\n"); 67 } 68 cnt =0; 69 for(int i = maxe_a;i>=0;i--){ 70 a[i] = (double)((int)(a[i]*10 + (a[i]<0?-0.5:0.5)))/10;//四舍五入處理 71 if(a[i]){ 72 cnt++; 73 } 74 } 75 if(cnt ==0){ 76 printf("0 0 0.0"); 77 }else{ 78 printf("%d",cnt); 79 for(int i=maxe_a;i>=0;i--){ 80 if(a[i]){ 81 printf(" %d %.1lf",i,a[i]); 82 } 83 } 84 } 85 return 0; 86 }View Code
最後總結一下,像這題可以作為多項式相除的模板題目。以後還可用於多項式的因式分解,求方程根等問題。
參考:cccc L2-018. 多項式A除以B
多項式A除以B