1. 程式人生 > >多項式A除以B

多項式A除以B

clu jpg com tail () 輸入格式 targe alt tar

這個問題我是在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

但非零多項式不能輸出零系數(包括舍入後為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