使用優先級隊列廣搜還是使用隊列廣搜

使用優先級隊列廣搜還是使用隊列廣搜

  1. 題目
    hdu網址:http://acm.hdu.edu.cn/showproblem.php?pid=1253
  2. 我的解答

2.1使用優先級隊列的廣搜,很清楚,每次只擴展時間最短的那一個分支,一定能找到最短的那個,如果大於T輸出-1,否則輸出時間。然而優先級隊列耗時,主要是優先級隊列的維護。

/**
 *   > File Name: runproblem.cpp
 *   > Author: yyHaker
 *   > Created Time: 2017/6/10
 *   使用優先級隊列超時
 */
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

int K,A,B,C,T;
int maze[55][55][55];
int vis[55][55][55];   //保存是否被訪問狀態以及到達改點的時間
int d[6][3]={1,0,0,
             -1,0,0,
             0,1,0,
             0,-1,0,
             0,0,1,
             0,0,-1};
struct node{
    int a,b,c;
    int time;
    friend bool operator<(node n1,node n2){  //優先級隊列的排序準則
        return n2.time<n1.time;
    }
};
//起點(0,0,0)->(A-1,B-1,C-1)
int bfs(){
    priority_queue<node> q;
    node s;
    s.a=0,s.b=0,s.c=0,s.time=0;
    vis[s.a][s.b][s.c]=1;
    q.push(s);
    while(!q.empty()){
        node t=q.top(); q.pop();
        if(t.a==A-1&&t.b==B-1&&t.c==C-1){
            return t.time;
        }
        if(t.time>T) return 0;
        node nn;
        for(int i=0;i<6;i++){
            nn.a=t.a+d[i][0];
            nn.b=t.b+d[i][1];
            nn.c=t.c+d[i][2];
            nn.time=t.time+1;
            if(nn.a>=0&&nn.a<A&&nn.b>=0&&nn.b<B&&nn.c>=0&&nn.c<C&&maze[nn.a][nn.b][nn.c]==0){
                if(!vis[nn.a][nn.b][nn.c]||(vis[nn.a][nn.b][nn.c]&&vis[nn.a][nn.b][nn.c]>nn.time)){   //訪問了的點可以被訪問,但是必須時間比以前短
                    q.push(nn);
                    vis[nn.a][nn.b][nn.c]=nn.time;  //記錄時間
                }
            }
        }
    }
    return 0;
}

int main(){
    scanf("%d",&K);
    while(K--){
        scanf("%d%d%d%d",&A,&B,&C,&T);
        for(int a=0;a<A;a++){
            for(int b=0;b<B;b++){
                for(int c=0;c<C;c++){
                    scanf("%d",&maze[a][b][c]);
                }
            }
        }
        //bfs
        memset(vis,0,sizeof(vis));
        int ans=bfs();
        //printf("%d\n",ans);
        if(ans==0||ans>T) printf("-1\n");
        else printf("%d\n",ans);
    }
}

2.2使用普通隊列的廣搜,擴展所有可能的分支,到達終點時即可得到最短時間。

/**
 *   > File Name: runproblem_queue.cpp
 *   > Author: yyHaker
 *   > Created Time: 2017/6/10
 *
 *   不使用優先級隊列就ac了
 */
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

int K,A,B,C,T;
int maze[55][55][55];
int vis[55][55][55];   //保存是否被訪問狀態以及到達改點的時間
int d[6][3]={1,0,0,
             -1,0,0,
             0,1,0,
             0,-1,0,
             0,0,1,
             0,0,-1};
struct node{
    int a,b,c;
    int time;
    friend bool operator<(node n1,node n2){  //優先級隊列的排序準則
        return n2.time<n1.time;
    }
};
//起點(0,0,0)->(A-1,B-1,C-1)
int bfs(){
   queue<node> q;
    node s;
    s.a=0,s.b=0,s.c=0,s.time=0;
    vis[s.a][s.b][s.c]=1;
    q.push(s);
    while(!q.empty()){
        node t=q.front(); q.pop();
        if(t.a==A-1&&t.b==B-1&&t.c==C-1){
            return t.time;
        }
        //if(t.time>T) return 0;
        node nn;
        for(int i=0;i<6;i++){
            nn.a=t.a+d[i][0];
            nn.b=t.b+d[i][1];
            nn.c=t.c+d[i][2];
            nn.time=t.time+1;
            if(nn.a>=0&&nn.a<A&&nn.b>=0&&nn.b<B&&nn.c>=0&&nn.c<C&&maze[nn.a][nn.b][nn.c]==0&&nn.time<=T){
                if(!vis[nn.a][nn.b][nn.c]||(vis[nn.a][nn.b][nn.c]&&vis[nn.a][nn.b][nn.c]>nn.time)){   //訪問了的點可以被訪問,但是必須時間比以前短
                    q.push(nn);
                    vis[nn.a][nn.b][nn.c]=nn.time;  //記錄時間
                }
            }
        }
    }
    return 0;
}

int main(){
    scanf("%d",&K);
    while(K--){
        scanf("%d%d%d%d",&A,&B,&C,&T);
        for(int a=0;a<A;a++){
            for(int b=0;b<B;b++){
                for(int c=0;c<C;c++){
                    scanf("%d",&maze[a][b][c]);
                }
            }
        }
        //bfs
        memset(vis,0,sizeof(vis));
        int ans=bfs();
        //printf("%d\n",ans);
        if(ans==0||ans>T) printf("-1\n");
        else printf("%d\n",ans);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章