问题(http://www.spoj.com/problems/BITMAP/)。我正在使用(https://medium.com/@arkro/spoj-bitmap-71d7a12354b1#.smnrwxcjv)上给出的优化方法。
以下是我的解决方案==>
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class BITMAP {
public static void print()
{
for(int i=0; i<r; i++)
{
System.out.println();
for(int j=0; j<c; j++)
System.out.print(a[i][j]+" ");
}
}
public static void bfs(int i1, int j1, int l)
{
a[i1][j1]=l;
int p[] = {-1,0,1};
Queue<Integer> qu = new LinkedList<Integer>();
qu.add(i1);qu.add(j1);
while(!qu.isEmpty())
{
int i= qu.remove();
int j= qu.remove();
for(int m=0;m<3;m++)
{
for(int n=0;n<3;n++)
{
int dist = Math.abs(p[m])+Math.abs(p[n]);
if((i+p[m] >-1 && i+p[m]<r) && (j+p[n] >-1 && j+p[n]<c) && a[i+p[m]][j+p[n]]>a[i][j]+dist)
{
a[i+p[m]][j+p[n]] = a[i][j]+dist;
qu.add(i+p[m]);qu.add(j+p[n]);
}
}
}
}
}
public static int a[][]= new int[182][182];
public static int r;
public static int c;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while(t--!=0)
{
r = in.nextInt();
c = in.nextInt();
ArrayList<int[]> l = new ArrayList<int[]>(); //Using it for storing all 1's location in the entire grid.
for(int i=0; i<r; i++)
{
String str = in.next();
for(int j=0; j<c; j++)
{
if(str.charAt(j)=='1')
l.add(new int[]{i,j});
a[i][j]=Integer.MAX_VALUE;
}
}
for(int[] k:l)
bfs(k[0],k[1],0);
print();
in.nextLine();
}
in.close();
}
}
我应该怎样做才能消除这个TLE问题?
答案 0 :(得分:0)
链接文章中描述的方法效率低下。它从棋盘上标有 1
的每个顶点开始 BFS 遍历。遍历以较少的步骤探索前一个 BFS 尚未到达的每个板顶点。这可能会导致多次探索某些顶点。
考虑以下示例:
1000000000000000000000
0000000000000000000001
有两个顶点标有 1
。第一个 BFS 将从左上角的 1
开始。它将探索整个棋盘,记录每个顶点到起始顶点的距离。第二个 BFS 将从右下角的 1
开始。它将探索棋盘的一半,直到到达离左上角 1
比离右下角 1
更近的顶点。因此,一半的棋盘已经被遍历了两次。
棋盘上的 1
越多,这个问题就越严重。以这个板子为例:
1111111111111111111111
0000000000000000000000
0000000000000000000000
0000000000000000000000
0000000000000000000000
第一个 BFS 将遍历整个板。第二个 BFS 必须探索除第一列之外的整个板(板上唯一比第二个 1
更靠近第一个 1
的地方)。第三个 BFS 再次探索除了前两列之外的整个板,依此类推。
此问题有一个简单的解决方法:您可以从所有 1
顶点同时开始,而不是为每个 1
执行单独的 BFS。这可以通过使用 1
顶点初始化 BFS 队列来完成。
然后 BFS 照常继续:它将遍历位于队列开头的 1
顶点,并将其未访问的邻居添加到队列末尾。因此,在从队列中移除所有 1
顶点后,BFS 将探索与任何 1
顶点距离为 1 的顶点。之后,它将探索与任何 1
顶点距离为 2 的顶点,依此类推。
这样,只需探索一次棋盘,而不是多次探索棋盘的某些部分。
除了超时问题,在你的实现中还有一个正确性问题:它对棋盘进行了 8 向遍历,而不是 4 向遍历(意味着你直线和对角走,而不是只直线).
问题描述中使用的度量是 Manhattan metric,它通过将两点在每个轴上的距离相加来测量两点之间的距离。因此,两个水平或垂直相邻的点的距离为 1,但两个对角相邻的点的距离为 2。因此,当您让 BFS 对角移动时,您错误地将对角相邻点之间的距离测量为 1 而不是 2。
要解决此问题,请限制您的 BFS 采取对角线步骤。