矩陣求和

矩陣求和ios

難度級別:A; 編程語言:不限;運行時間限制:3000ms; 運行空間限制:256000KB; 代碼長度限制:2000000B編程

試題描述數組

矩陣求和編程語言

輸入ide

第一行n和m,表示行數和列數
接下來n行表示矩陣
再來一行一個整數q,表示詢問個數
接下來q行,每行四個整數x1,y1,x2,y2表示左上右下的座標spa

輸出code

對於每一個詢問輸出一個整數表示該矩陣範圍內的整數和blog

輸入示例ci

5 5
1 2 5 4 1
1 1 7 6 8
8 7 9 5 2
4 4 4 1 8
5 10 11 13 7
3
2 1 4 3
2 2 5 5
4 1 5 4io

輸出示例

45
103
52

其餘說明

n,m < 2001
q < 100001
矩陣內全部數小於2000

代碼:

 1 #include<iostream>
 2 
 3 int a,m,n,i,j,k,x1,y1,x2,y2;
 4 
 5 long long sum,s[2002][2002]={0};//數組s用來儲存前綴和
 6 
 7 using namespace std;
 8 
 9 int main()
10 
11 {
12 
13             scanf("%d%d",&m,&n);
14 
15 for(i=1;i<=m;i++)//輸入,賦值二維數組s
16 
17                 for(j=1;j<=n;j++)
18 
19                 {
20 
21                      scanf("%d",&a);//爲了節省空間,以單個變量輸入
22 
23                      s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
24 
25                 }
26 
27             scanf("%d",&k);
28 
29             while(k--)
30 
31             {
32 
33                  scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
34 
35                  sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
36 
37                  printf("%lld\n",sum);
38 
39             }
40 
41 }
View Code

代碼分析:

有三種方法:

1.    直接求解,按單個元素記錄。所以,k次查詢裏每次都要有兩個循環,一個橫着在這個區間裏掃描,另外一個豎着掃描。

代碼以下:

 1 #include<iostream>
 2 
 3 int a[2010][2010],m,n,i,j,k,b,c,d,e;
 4 
 5 long long sum;
 6 
 7 using namespace std;
 8 
 9 int main()
10 
11 {
12 
13     scanf("%d%d",&m,&n);
14 
15     for(i=1;i<=m;i++)
16 
17     {
18 
19         for(j=1;j<=n;j++)
20 
21         scanf("%d",&a[i][j]);
22 
23     }
24 
25     cin>>k;
26 
27     while(k--)
28 
29     {
30 
31         sum=0;
32 
33         scanf("%d%d%d%d",&b,&c,&d,&e);
34 
35         for(i=b;i<=d;i++)//兩次循環
36 
37             for(j=c;j<=e;j++)
38 
39                 sum+=a[i][j];
40 
41         printf("%lld\n",sum);
42 
43                
44 
45     }
46 
47 }
View Code

這個方法顯然效率過低,兩次循環太耗費時間了,因此要考慮運用前綴和的辦法了。

2.    利用以前數組儲存前綴和的辦法,給這個二維數組每行都求一個前綴和,而後在查詢時,用要求的區間當中每一行的從y1到y2的和,用s[x][y2]-s[x][y1-1](x爲第x行)

因此採用這個方法效率比上一個方法更快。

代碼:

 1 #include<iostream>
 2 
 3 int a,m,n,i,j,k,b,c,d,e,s[2002][2002]={0};
 4 
 5 long long sum;
 6 
 7 int main()
 8 
 9 {
10 
11     scanf("%d%d",&m,&n);
12 
13     for(i=1;i<=m;i++)
14 
15         for(j=1;j<=n;j++)
16 
17         {
18 
19             scanf("%d",&a);
20 
21             s[i][j]=s[i][j-1]+a;
22 
23         }
24 
25     scanf("%d",&k);
26 
27     while(k--)
28 
29     {
30 
31         sum=0;
32 
33         scanf("%d%d%d%d",&b,&c,&d,&e);
34 
35         for(i=b;i<=d;i++)
36 
37             sum+=(s[i][e]-s[i][c-1]);
38 
39         printf("%lld\n",sum);
40 
41     }
42 
43 }
View Code

這個方法不用兩次循環,可仍是有一次循環,但這還不能使人滿意,有沒有更快的方法呢?

分析上兩個方法,咱們發現:

這是第一個方法,它是以單個元素來求解的(以點作前綴和的)。一步步來累加。

第二個方法,前綴和,至關因而以行作單位求解。

既然,以行作前綴和的有了,    以點作前綴和的有了,那能不能以面作前綴和呢?

分析以下:

如此,推算賦值公式就如韋恩圖那樣:

 

把s[i-1][j]和s[i][j-1]加起來,s[i-1][j-1]部分重疊了,因此要減去,在加上輸入的a,就獲得:

s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;

而輸出就也像上面同樣,s[x2][y2]是從座標(11)開始的,因此要減去s[x2][y1-1]s[x1-1][y2],s[x1-1][y1-1]被多減了,因此要加上。

代碼:

 1 #include<iostream>
 2 
 3 long long sum,a,m,n,i,j,k,x1,y1,x2,y2,s[2002][2002]={0};
 4 
 5 using namespace std;
 6 
 7 int main()
 8 
 9 {
10 
11     scanf("%d%d",&m,&n);
12 
13     for(i=1;i<=m;i++)
14 
15         for(j=1;j<=n;j++)
16 
17         {
18 
19             scanf("%d",&a);
20 
21             s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
22 
23         }
24 
25     scanf("%d",&k);
26 
27     while(k--)
28 
29     {
30 
31         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
32 
33         sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
34 
35         printf("%lld\n",sum);
36 
37     }
38 
39 }
View Code

這個方法只用一次運算便求出瞭解,因此它是三個方法中最快的方法。

相關文章
相關標籤/搜索