zoukankan      html  css  js  c++  java
  • ZJNU 2018

    ZJNU 2018 - Portal

    题面

    一个人要从图中的(C)点走到(F)​​点。

    每一秒他可以往上下左右四个方向走一步,只要目标点不是墙'#'。

    另外,他可以通过神奇的枪在墙上开两个传送门,枪可以射中上下左右四个方向第一次遇到的墙;如果他站在有传送门的墙边,他就可以花一秒穿越传送门到另外一个传送门面对的点上。

    射击产生传送门所花费的时间不计。

    传送门同一时间最多存在两个。一旦他射击产生了第三个传送门,那么第一个传送门将会自动消失。

    问从点(C)走到点(F)的最短时间。


    思路

    考虑直接BFS搜索

    除了常规四个方向外,本题还可以使用传送门进行传送

    所以可以预处理出某一点(P)​向四个方向射击能产生传送门的位置(Q)​(即某一方向最近的墙的位置),那么从点(P)​​通过传送门来到墙边这一点(Q)​​所需要花费的时间也就是距离点(P)​​​最近的墙的距离(+1)

    对于上下左右四个方向最近墙的位置,(O(n^2))预处理即可

    而对于某个点最近的墙的距离,以墙为起点先搜索一遍整张图,处理完后再BFS起点到终点计算答案


    #include<bits/stdc++.h>
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    #define all(a) (a).begin(),(a).end()
    #define SUM(a) accumulate(all(a),0LL)
    #define MIN(a) (*min_element(all(a)))
    #define MAX(a) (*max_element(all(a)))
    #define mst(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int INF=0x3f3f3f3f;
    const ll LINF=0x3f3f3f3f3f3f3f3f;
    const double eps=1e-12;
    const double PI=acos(-1.0);
    const ll mod=998244353;
    const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
    void debug(){cerr<<'
    ';}template<typename T,typename... Args>void debug(T x,Args... args){cerr<<"[ "<<x<< " ] , ";debug(args...);}
    mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
    ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
    ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
    ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
    ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
    ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}
    
    int n,m;
    char mp[505][505];
    int sx,sy,tx,ty;
    int lef[505][505],rig[505][505],top[505][505],btm[505][505];
    int dis[505][505],rdis[505][505];
    
    inline bool prim(int x,int y)
    {
        return x>0&&y>0&&x<=n&&y<=m;
    }
    
    void solve()
    {
        rep(i,1,n)
            cin>>(mp[i]+1);
            
        queue<pii> q;
        mst(dis,INF);
        mst(rdis,INF); //某点最近的墙的距离
        
        rep(i,1,n)
            rep(j,1,m)
            {
                if(mp[i][j]=='C')
                    sx=i,sy=j;
                else if(mp[i][j]=='F')
                    tx=i,ty=j;
                else if(mp[i][j]=='#')
                {
                    repp(k,0,4)
                    {
                        int x=dx[k]+i,y=dy[k]+j;
                        if(rdis[x][y]==0)
                            continue;
                        if(prim(x,y)&&mp[x][y]!='#')
                            q.push(pii(x,y)),rdis[x][y]=0;
                    }
                }
            }
        
        while(!q.empty()) //先预处理rdis
        {
            int x=q.front().fi,y=q.front().se;
            q.pop();
            repp(i,0,4)
            {
                int px=x+dx[i],py=y+dy[i];
                if(prim(px,py)&&mp[px][py]!='#')
                {
                    if(rdis[px][py]>rdis[x][y]+1)
                    {
                        rdis[px][py]=rdis[x][y]+1;
                        q.push(pii(px,py));
                    }
                }
            }
        }
        
        rep(i,1,n) //处理四个方向上传送门能够到达的点
        {
            int t=0;
            rep(j,1,m)
            {
                if(mp[i][j]=='#')
                {
                    t=j;
                    continue;
                }
                lef[i][j]=t+1;
            }
            t=n+1;
            per(j,m,1)
            {
                if(mp[i][j]=='#')
                {
                    t=j;
                    continue;
                }
                rig[i][j]=t-1;
            }
        }
        rep(j,1,m)
        {
            int t=0;
            rep(i,1,n)
            {
                if(mp[i][j]=='#')
                {
                    t=i;
                    continue;
                }
                top[i][j]=t+1;
            }
            t=n+1;
            per(i,n,1)
            {
                if(mp[i][j]=='#')
                {
                    t=i;
                    continue;
                }
                btm[i][j]=t-1;
            }
        }
        
        q.push(pii(sx,sy));
        dis[sx][sy]=0;
        
        while(!q.empty())
        {
            int x=q.front().fi,y=q.front().se;
            q.pop();
            repp(i,0,4) //普通的四个方向
            {
                int px=x+dx[i],py=y+dy[i];
                if(prim(px,py)&&mp[px][py]!='#')
                {
                    if(dis[px][py]>dis[x][y]+1)
                    {
                        dis[px][py]=dis[x][y]+1;
                        q.push(pii(px,py));
                    }
                }
            }
            int px,py;
            px=x,py=lef[x][y]; //向左射击产生传送门能到达的点
            if(prim(px,py)&&mp[px][py]!='#')
            {
                if(dis[px][py]>dis[x][y]+rdis[x][y]+1)
                {
                    dis[px][py]=dis[x][y]+rdis[x][y]+1;
                    q.push(pii(px,py));
                }
            }
            px=x,py=rig[x][y];
            if(prim(px,py)&&mp[px][py]!='#')
            {
                if(dis[px][py]>dis[x][y]+rdis[x][y]+1)
                {
                    dis[px][py]=dis[x][y]+rdis[x][y]+1;
                    q.push(pii(px,py));
                }
            }
            px=top[x][y],py=y;
            if(prim(px,py)&&mp[px][py]!='#')
            {
                if(dis[px][py]>dis[x][y]+rdis[x][y]+1)
                {
                    dis[px][py]=dis[x][y]+rdis[x][y]+1;
                    q.push(pii(px,py));
                }
            }
            px=btm[x][y],py=y;
            if(prim(px,py)&&mp[px][py]!='#')
            {
                if(dis[px][py]>dis[x][y]+rdis[x][y]+1)
                {
                    dis[px][py]=dis[x][y]+rdis[x][y]+1;
                    q.push(pii(px,py));
                }
            }
        }
        if(dis[tx][ty]==INF)
            cout<<"nemoguce
    ";
        else
            cout<<dis[tx][ty]<<'
    ';
    }
    int main()
    {
        closeSync;
        while(cin>>n>>m)
        {
            solve();
        }
        return 0;
    }
    

  • 相关阅读:
    斗鱼扩展--localStorage备份与导出(九)
    斗鱼扩展--管理移除房间(八)
    斗鱼扩展--让你看到更多内容(七)
    Ubuntu18.04 安装水星1300M无线网卡
    Course1_Week1_ProgrammingHomeWork
    找出3个数中不为-1的最小数
    马拉车算法
    偏差-方差分解
    决策树如何防止过拟合
    可视化数据集两个类别变量的关系
  • 原文地址:https://www.cnblogs.com/stelayuri/p/15138166.html
Copyright © 2011-2022 走看看