201604-4游戏【启发式算法 46ms】

注意点有如下几个:
1.找最短路用bfs遍历;
2.一开始我是用danger结构体记录危险块的物理位置和危险时间,然后每次进行遍历,显然,danger块数∈[1,9999],地图的最大规格是100×100,危险时间∈[0,100],极端情况下最短路径最大会是300【为什么会是300:结合变量的取值范围思考】,也就是最差情况下有4^300个节点,如果每走一个节点都遍历danger块,复杂度就是O(2^600 * 10^4),差不多就是O(10^184)…妥妥超时….所以牺牲空间换时间,用vis数组进行记录每个块是否安全。
3.往常vis数组是二维的,只记录了行数与列数,但是这里又有加时间的维度,所以就是三维数组。同时,vis数组还起到了防止重复访问相同节点的作用(这里的节点的唯一性不仅由位置标出,还与时间有关)
4.看网上的其他题解都是用queue存储,其实可以用priority_queue,优先级改成启发式:当前时间+n-x+m-y【n-x+m-y是当前位置到达n行m列的位置的最短时间】,虽然priority_queue存取比queue慢,但是用了启发式以后还是76ms降到了46ms

代码如下:

//启发式算法 46ms
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<limits.h>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#define iter(i,start,end) for(int (i)=(start);(i)<(end);(i)++)
#define vi vector<int> 
using namespace std;
struct danger
{
    int x,y,t1,t2;
    danger(int a,int b,int c,int d):x(a),y(b),t1(c),t2(d){};
};
struct node
{
    int x,y,t;
    node(int a,int b,int c):x(a),y(b),t(c){};
};
struct cmp
{
    bool operator()(node a ,node b)
        {return a.t-a.x-a.y>b.t-b.x-b.y;}           
    // {return a.t>b.t;}
};

const int nmax=100+5;   const int mmax=100+5;   
int  n,m,t;  //n,m \in [1,100] t \in [0,9998]
int kcase;
vector<danger> dangers;
int vis[nmax][mmax][300+5]; //
int xdir[4]={0,-1,0,1};      int ydir[4]={-1,0,1,0};
//← ↑ → ↓

void init();
void solve();
int main()
{
    //freopen("201604-4.txt","r",stdin);
    kcase=0;    
    while(scanf("%d %d %d",&n,&m,&t)==3)
    {
        kcase++;
        init();
        solve();
    }
    return 0;
}

bool ok(int i,int j,int t)
{
    if(i<0 || i>=n || j<0 || j>=m)  return false;
    if(vis[i][j][t]==kcase) return false;
    return true;
}

void solve()
{
    // queue<node> q;
    priority_queue<node,vector<node>,cmp> q;
     q.push(node(0,0,0));        //【改成启发式算法的话,改下cmp函数就可以了】
    vis[0][0][0]=kcase;
    while(q.size())
    {
        node now=q.top();//front(); 
        q.pop();
        int x=now.x,y=now.y,time=now.t;

         // cout<<"当前正在处理的:("<<x<<","<<y<<","<<time<<")\n";
        iter(i,0,4)
        {
            int newx=x+xdir[i],newy=y+ydir[i];
            if(ok(newx,newy,time+1))
            {
                if(newx==n-1 && newy==m-1 )
                {
                    cout<<time+1<<endl;
                    return;
                }
                 // cout<<"\t压进点:("<<newx<<","<<newy<<","<<time+1<<")\n";
                vis[newx][newy][time+1]=kcase;
                q.push(node(newx,newy,time+1));
            }
        }
    }
}

void init()
{
    int a,b,c,d;
    iter(i,0,t){
        cin>>a>>b>>c>>d;    
        iter(j,c,d+1)
            vis[a-1][b-1][j]=kcase;
    }
    原文作者:启发式算法
    原文地址: https://blog.csdn.net/Hesy_H/article/details/82461908
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞