前一阵子搞教材和其他事情,把博客给落下了。最近趁着找题目的机会,再争取多记录点博客题目。
每日一题最近不能按顺序了,找题目优先了。只能先这样了。

题目描述:
有两个人分别地图上的两个位置,现在两个人要相遇,问最短时间。一个人走8个方向每次一步,另一个走4个方向每次两步。(n,m<=1000)

思路:
经典bfs问题。
两个人相遇问题,显然一个比较常用的方法是离线处理。
先bfs第一个人,记录下他到每个点的最少时间。
接着bfs第二个人,也记录到每个点的最少时间。
那么如果两人能在某个点相遇,相遇时间就是两人中时间大的那个。最后枚举所有的点,找一个最小的值。
注意走两步的处理,在下面的代码中我处理成了走一步花0.5秒,最后计算的时候向上取整。
代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,v[2][1003][1002];
double d[2][1003][1004],pd;
char s[1004][1004];
pair<int,int>p[2];
int dir[][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
struct node{
    int x,y;
    double step;
};
bool check(int a,int b){
    if(s[a][b]=='#')return false;
    return true;
}
void bfs(int w){
    queue<node>qu;
    node tmp;
    tmp.x=p[w].first;tmp.y=p[w].second;
    tmp.step=0;
    qu.push(tmp);
    v[w][tmp.x][tmp.y]=1;
    while(qu.size()){
        node now=qu.front();
        qu.pop();
        for(int i=0;i<(w?4:8);i++){
            node tmp;
            tmp.x=now.x+dir[i][0];
            tmp.y=now.y+dir[i][1];
            tmp.step=now.step+1;
            if(w){
                tmp.x=now.x+dir[i][0];
                tmp.y=now.y+dir[i][1];
                tmp.step=now.step+0.5;
            }

            if(s[tmp.x][tmp.y]=='#')continue;
            if(v[w][tmp.x][tmp.y])continue;
            v[w][tmp.x][tmp.y]=1;
            d[w][tmp.x][tmp.y]=tmp.step;
            qu.push(tmp);
        }
    }
}
int main()
{
    cin>>n>>m;
    getchar();
    for(int i=1;i<=n;i++){
        string ts;
        getline(cin,ts);
        int cnt=0;
        for(int j=0;j<ts.size();j++){
            if(ts[j]!=' ')s[i][++cnt]=ts[j];
        }
    }
    for(int i=0;i<=n+1;i++){
        for(int j=0;j<=m+1;j++){
            if(i==0||j==0||i==n+1||j==m+1)s[i][j]='#';
            if(s[i][j]=='C')p[0]=make_pair(i,j);
            if(s[i][j]=='D')p[1]=make_pair(i,j);
        }
    }
    bfs(0);
    bfs(1);
    int ans=1e7+7;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]=='#')continue;
            if(!v[0][i][j]||!v[1][i][j])continue;
            ans=min(ans,max(int(d[0][i][j]),int(d[1][i][j]+0.5)));
        }
    }
    if(ans==1e7+7)cout<<"NO"<<endl;
    else
    cout<<"YES"<<endl<<ans<<endl;
    return 0;
}

方法二:
用双向广搜。双向广搜思路是从两个地方分别开始广搜,每次只扩展一层。然后判断是否能在当前层相遇,如果相遇了就可以退出了。这里处理两步的做法是分成2次1步走,扩展到同一层。即做第二个人每次做2次bfs。
代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,v[2][1003][1002];
double d[2][1003][1004];
char s[1004][1004];
pair<int,int>p[2];
int dir[][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
struct node{
    int x,y;
    double step;
};
bool check(int a,int b){
    if(s[a][b]=='#')return false;
    return true;
}
queue<node>q1,q2;
int main()
{
    cin>>n>>m;
    getchar();
    for(int i=1;i<=n;i++){
        string ts;
        getline(cin,ts);
        int cnt=0;
        for(int j=0;j<ts.size();j++){
            if(ts[j]!=' ')s[i][++cnt]=ts[j];
        }
    }
    for(int i=0;i<=n+1;i++){
        for(int j=0;j<=m+1;j++){
            if(i==0||j==0||i==n+1||j==m+1)s[i][j]='#';
            if(s[i][j]=='C')p[0]=make_pair(i,j);
            if(s[i][j]=='D')p[1]=make_pair(i,j);
        }
    }
    node tmp;
    tmp.x=p[0].first;tmp.y=p[0].second;
    v[0][tmp.x][tmp.y]=1;
    q1.push(tmp);
    tmp.x=p[1].first;tmp.y=p[1].second;
    v[1][tmp.x][tmp.y]=1;
    q2.push(tmp);
    int timi=0;
    int flag=0;
    while(!flag){
        timi++;
        int cur1,cur2;
        cur1=q1.size();
        cur2=q2.size();
        if(cur1==0&&cur2==0){
            flag=-1;
            break;
        } 
        while(q1.size()&&cur1--){
            node now=q1.front();
            q1.pop();
            for(int i=0;i<8;i++){
                node tmp;
                tmp.x=now.x+dir[i][0];tmp.y=now.y+dir[i][1];
                if(v[1][tmp.x][tmp.y]){
                    flag=1;break;
                }
                if(check(tmp.x,tmp.y)&&!v[0][tmp.x][tmp.y]){
                    v[0][tmp.x][tmp.y]=1;
                    q1.push(tmp);
                }
            }
        }

        while(q2.size()&&cur2--){
            node now=q2.front();
            q2.pop();
            for(int i=0;i<4;i++){
                node tmp;
                tmp.x=now.x+dir[i][0];tmp.y=now.y+dir[i][1];
                if(v[0][tmp.x][tmp.y]){
                    flag=true;
                    break;
                }
                if(v[0][tmp.x][tmp.y]){
                    flag=1;break;
                }
                if(check(tmp.x,tmp.y)&&!v[1][tmp.x][tmp.y]){
                    v[1][tmp.x][tmp.y]=1;
                    q2.push(tmp);
                }
            }
        }
        if(flag==1)break;
        cur2=q2.size();
        while(q2.size()&&cur2--){
            node now=q2.front();
            q2.pop();
            for(int i=0;i<4;i++){
                node tmp;
                tmp.x=now.x+dir[i][0];tmp.y=now.y+dir[i][1];
                if(v[0][tmp.x][tmp.y]){
                    flag=true;
                    break;
                }
                if(check(tmp.x,tmp.y)&&!v[1][tmp.x][tmp.y]){
                    v[1][tmp.x][tmp.y]=1;
                    q2.push(tmp);
                }
            }
        }
    }
    if(flag==-1)cout<<"NO"<<endl;
    else {
        cout<<"YES"<<endl<<timi<<endl;
    }
    return 0;
}