BFS求多特征点最短路 以及 二维“和数组”

来源:互联网 发布:mysql重置初始密码 编辑:程序博客网 时间:2024/06/08 16:09

城市统计
Time Limits: 1000 ms
Memory Limits: 128000 KB

Description

  中山市的地图是一个n*n的矩阵,其中标号为1的表示商业区,标号为0的表示居民区。为了考察市内居民区与商业区的距离,并对此作出评估,市长希望你能够编写一个程序完成这一任务。
  居民区i到商业区的距离指的是到距离它最近的商业区j的距离(|Xi-Xj|+|Yi-Yj|),而你将统计的是对于城市中的每一个区域k,以它为中心,所有满足max(|Xk-Xm|,|Yk-Ym|)<=r的区域m到商业区距离之和。结果同样以n*n的矩阵形式输出。

Input

第一行为t,表示以下有t组数据,每组数据之间以空行隔开,以下:
第一行为n,r(1 < =r < n < =150)   
第二行起为一个n*n的矩阵。

Output

  t组n*n的矩阵。每组用空行隔开

Sample Input

Sample Input1:
1
4 1
1 0 0 0
1 1 0 0
0 1 1 0
0 1 0 0

Sample Input2:
2
10 4
1 0 0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 0 0 1 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 1 0 0 1 0 0 0
0 0 1 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0 0 1

10 9
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1

Sample Output

Sample Output1:
1 4 9 8
2 5 10 9
2 4 7 7
2 3 4 4

Sample Output2:
40 50 57 63 70 70 63 57 50 40
50 60 68 76 86 86 76 68 60 50
57 68 76 85 97 97 85 76 68 57
63 76 85 94 107 107 94 85 76 63
70 86 97 107 120 120 107 97 86 70
70 86 97 107 120 120 107 97 86 70
63 76 85 94 107 107 94 85 76 63
57 68 76 85 97 97 85 76 68 57
50 60 68 76 86 86 76 68 60 50
40 50 57 63 70 70 63 57 50 40

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

这道题的思路很清晰:先使用 BFS 计算出每个点的距离,然后对每个点进行加的操作。关键在于如何实现这两点。

思路1:搜索每一个居民区,找到的第一个商业区就是这个点的距离。获得距离后对每个点再进行加的操作。前者的时间复杂度约为O(n^2),后者的时间复杂度很糟糕,约为O(n^3)。
这样只能得40分。

思路2:
使用BFS前,直接把所有的商业区放入队列中,并将商业区的距离置0。然后一直搜索,直到所有点的距离都计算出来,队列自然为空。这样做能够不保存每个点是居民区还是商业区。时间复杂度比O(n^2)稍小。
然后是求和。首先将之前的距离 矩形数组 进行类似于一维数组的求和优化:

    for(int i=1; i<=n; i++)    {        for(int j=1; j<=n; j++)        {            rect[i][j]+=rect[i-1][j]+rect[i][j-1]-rect[i-1][j-1];        }    }

注意公式的推导。
然后用一维数组求和类似的方法对点对应的区域求和。

    RECT R(i-r,j-r,i+r,j+r);    printf("%d ",R.sum());
struct RECT{    int left;    int right;    int top;    int bottom;    RECT(int left,int top,int right,int bottom):left(left),right(right),top(top),bottom(bottom)    {    }    void fixRect() //防止出界    {        left=std::max(1,left);        right=std::min(n,right);        top=std::max(1,top);        bottom=std::min(n,bottom);    }    int sum()    {        fixRect();        return rect[right][bottom]-rect[left-1][bottom]-        rect[right][top-1]+rect[left-1][top-1]; //重点    }};

对矩阵的初始化的时间复杂度为O(n^2),而查询每个点的时间复杂度为O(n^2),整个程序的时间复杂度不超过O(n^2),完全在可接受的范围内。

参考代码

#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <string>#include <iostream>#include <algorithm>#include <vector>#include <stack>#include <queue>#include <deque>#include <map>#include <set>using std::cin;using std::cout;using std::endl;int n,r;std::vector<std::vector<int> > rect;template<typename T>void setVector(std::vector<std::vector<T> > &vec, int x, int y, T var = 0){    vec.clear();    vec.resize(x);    for(int i=0; i<x; i++)    {        vec[i].resize(y,var);    }}const int vecx[]= {1,-1,0,0};const int vecy[]= {0,0,1,-1};struct node{    int x,y;    int length;    node(int x,int y,int length):x(x),y(y),length(length)    {    }};struct RECT{    int left;    int right;    int top;    int bottom;    RECT(int left,int top,int right,int bottom):left(left),right(right),top(top),bottom(bottom)    {    }    void fixRect()    {        left=std::max(1,left);        right=std::min(n,right);        top=std::max(1,top);        bottom=std::min(n,bottom);    }    int sum()    {        fixRect();        return rect[right][bottom]-rect[left-1][bottom]-rect[right][top-1]+rect[left-1][top-1];    }};void run(){    scanf("%d%d",&n,&r);    setVector(rect,n+1,n+1,-1);    std::queue<node> Queue;    for(int i=1; i<=n; i++)    {        for(int j=1; j<=n; j++)        {            int type;            scanf("%d",&type);            if(type)            {                Queue.push(node(i,j,0));                rect[i][j]=0;            }        }    }    for(int i=0; i<=n; i++)    {        rect[i][0]=0;        rect[0][i]=0;    }    //直接获取距离,不保存类型    while(Queue.size())    {        node temp=Queue.front();        Queue.pop();        for(int i=0; i<4; i++)        {            int newx=temp.x+vecx[i];            int newy=temp.y+vecy[i];            if(newx>0 && newx<=n && newy>0 && newy<=n && rect[newx][newy]==-1)            {                Queue.push(node(newx,newy,temp.length+1));                rect[newx][newy]=temp.length+1;            }        }    }    //获取距离和    for(int i=1; i<=n; i++)    {        for(int j=1; j<=n; j++)        {            rect[i][j]+=rect[i-1][j]+rect[i][j-1]-rect[i-1][j-1];        }    }    //得到答案    for(int i=1; i<=n; i++)    {        for(int j=1; j<=n; j++)        {            RECT R(i-r,j-r,i+r,j+r);            printf("%d ",R.sum());        }        puts("");    }}int main(){    int a;    scanf("%d",&a);    while(a--)    {        run();        if(a) puts(""); //Notice!!!     }    return 0;}

这份代码的结构写的有点渣,但这不是重点。重点是记得要每组数据换行!不然你写得再好,算得再快,还是会因为格式不对只能得到只有1组数据的那个10分!