UOJ Logo xuruiyang的博客

博客

8.20GLX附加赛T2题解

2018-08-21 11:55:17 By xuruiyang

写在前面(可自行跳过)

  • 我的解法显然不是最优的,不值得抄,毕竟我不(fei)会(chang)卡(de)常(cai)

  • 请原谅我奇丑无比的博客,毕竟我不(fei)会(chang)美(de)化(cai)

一句话题意

给定一个长方形网格,求网格上每个点到一个目标点最少的拐弯次数。

下面是主要部分↓

鼓掌熊

题解

口糊

显然是个最短路。可以考虑用一个类似SPFA的算法。

一开始,把所有关键点加入队列,距离设为0,其他点距离为INF。然后进行SPFA对于每个点,向四个方向枚举直到出边界或者碰到障碍,对于每个枚举到的点,用当前点的最小次数+1更新枚举点的最小次数,然后O(1)回答。

但是我们知道SPFA是不稳定的。

可是这道题的(假的)SPFA是稳定的$n^2$。因为每次更新的增加量(也就是平时FPFA中的边权)是固定的1,所以按入对顺序排好每个点后,其答案是递增的。这保证了每个点只入队一次,点数是$n^2$的。同时因为这条性质,我的代码中有很多操作是多余的,但是太懒就没去改。

AC代码

(这道题还有个坑,就是每行末尾不能输出多余空格,但是可以在末尾输出多余空行)

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
struct Pair{
    int x,y;
}tmp;
int n,m,mn[2010][2010],x,y,vis[2010][2010];
char c[2010][2010];
queue<Pair>q;
void getc(char &c){
    c=getchar();
    while(c==' '||c=='\n'){
        c=getchar();
    }
}
void SP(){
    while(!q.empty()){
        tmp=q.front();
        x=tmp.x;
        y=tmp.y;
        q.pop();
        for(int i=1;x+i<=n&&c[x+i][y]!='#';i++){
            if(mn[x+i][y]>mn[x][y]+1){
                mn[x+i][y]=mn[x][y]+1;
                if(!vis[x+i][y]){
                    vis[x+i][y]=1;
                    tmp.x=x+i;
                    tmp.y=y;
                    q.push(tmp);
                }
            }
        }
        for(int i=1;x-i>=1&&c[x-i][y]!='#';i++){
            if(mn[x-i][y]>mn[x][y]+1){
                mn[x-i][y]=mn[x][y]+1;
                if(!vis[x-i][y]){
                    vis[x-i][y]=1;
                    tmp.x=x-i;
                    tmp.y=y;
                    q.push(tmp);
                }
            }
        }
        for(int i=1;y+i<=m&&c[x][y+i]!='#';i++){
            if(mn[x][y+i]>mn[x][y]+1){
                mn[x][y+i]=mn[x][y]+1;
                if(!vis[x][y+i]){
                    vis[x][y+i]=1;
                    tmp.x=x;
                    tmp.y=y+i;
                    q.push(tmp);
                }
            }
        }
        for(int i=1;y-i>=1&&c[x][y-i]!='#';i++){
            if(mn[x][y-i]>mn[x][y]+1){
                mn[x][y-i]=mn[x][y]+1;
                if(!vis[x][y-i]){
                    vis[x][y-i]=1;
                    tmp.x=x;
                    tmp.y=y-i;
                    q.push(tmp);
                }
            }
        }
        vis[x][y]=0;
    }
}
void print(int x){
    if(x>9){
        print(x/10);
    }
    putchar(x%10+'0');
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            getc(c[i][j]);
            if(c[i][j]=='+'){
                mn[i][j]=0;
                tmp.x=i;
                tmp.y=j;
                q.push(tmp);
                vis[i][j]=1;
            }else{
                mn[i][j]=INF;
            }
        }
    }
    SP();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(c[i][j]=='#'){
                putchar('#');
            }else{
                if(mn[i][j]>=INF){
                    putchar('X');
                }else{
                    print(mn[i][j]);
                }
            }
            if(j!=m){
                putchar(' ');
            }
        }
        puts("");
    }
    return 0;
}

评论

xuruiyang
喜欢的话就点一下题解右边那个向下的手谢谢OVO
  • 2018-08-21 12:22:02
HUHAO
@xuruiyang dalao太虐了,比我的垃圾卡常SB方法不知道高到哪里去了, #%%%xry巨佬
  • 2018-08-21 13:11:21
xuruiyang
-----------------------------------------------------------以下是大佬的评论---------------------------------------------------------------------------------
  • 2018-08-21 13:11:33
QYJ
太巨了!
  • 2018-08-21 18:13:22
wahuoneinv
太强了
  • 2018-08-22 08:26:59