【算法设计与分析】地毯【差分】【Java实现】【P3397】
先来个原题链接:
链接: 地毯
问题描述:
在 n×n 的格子上有 m 个地毯。给出这些地毯的信息,问每个点被多少个地毯覆盖
解题算法思路:
二维差分前缀和a[][]的计算用到了递推公式:
a[i][j]=D[i][j]+a[i−1][j]+a[i][j−1]−a[i−1][j−1]
代码中29行到36行用D[][]推出a[][]并打印出来。为了节约空间,可以不定义a[][],而是把用过的D[][]看成a[][]。这是因为用过一遍之后就不会在使用原数据了,所以可以想成滚动数组。
源代码:
1.import java.io.BufferedReader;
2.import java.io.IOException;
3.import java.io.InputStreamReader;
4.
5.public class carpet {//差分——地毯
6. public static void main() throws IOException {
7.
8. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
9. //Scanner sc =new Scanner(System.in);太慢了,BR缓冲区快一倍
10. String[] temp = br.readLine().split(" ");
11. int[][] D =new int[1050][1050];
12. //int a[5000][5000]; //原数组,不定义也行
13. int n=Integer.parseInt(temp[0]);
14. int m=Integer.parseInt(temp[1]);
15.
16. while(m!=0) {
17. m--;
18. String[] str =br.readLine().split(" ");
19. int x1=Integer.parseInt(str[0]);
20. int y1=Integer.parseInt(str[1]);
21. int x2=Integer.parseInt(str[2]);
22. int y2=Integer.parseInt(str[3]);
23.
24. D[x1][y1] += 1; //计算差分数组
25. D[x2+1][y1] -= 1;
26. D[x1][y2+1] -= 1;
27. D[x2+1][y2+1] += 1;
28. }
29. for(int i=1;i<=n;i++) {
30. for(int j=1;j<=n;j++) {
31. //a[i][j] = D[i][j] + a[i-1][j] + a[i][j-1] - a[i-1][j-1];
32. //printf("%d ",a[i][j]); //这两行和下面两行的效果一样
33. D[i][j] += D[i-1][j]+D[i][j-1]-D[i-1][j-1];
34. System.out.print(D[i][j]);
35. }
36. System.out.println();
37. }
38. UI.main();
39. }
40.}
算法效率分析:
这道题是很经典的差分题。在用差分之前,先考虑能不能用暴力法。每次修改复杂度是O(n^2),
共m次,总复杂度O(m×n^2),超时。
二维差分的复杂度是多少?一维差分的一次修改是O(1)的,二维差分的修改估计也是O(1)的;一维差分的一次查询是O(n)的,二维差分是 O(n ^ 2)的,所以二维差分的总复杂度是O(m + n ^ 2)由于计算一次二维矩阵的值需要O(n^2)次计算,所以二维差分已经达到了最好的复杂度。