51nod 1572 宝岛地图 (预处理四个方向的最大步数优化时间,时间复杂度O(n*m+k))

题目:

这题如果没有时间限制的话暴力可以解,暴力的话时间复杂度大概是O(k*n),1s的话非常悬。

所以我们需要换个思路,我们对每个点预处理四个方向最多能走的步数,这个预处理时间复杂度是O(n*m)。

然后对每个字母点模拟一下即可。总时间复杂度O(n*m+k)。不会超时。

提示:没有满足要求的点时,要输出"no solution",我就在这个上面WA了一次,不然应该可以一次AC的。

代码:

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <queue> 
using namespace std;
typedef long long ll;
#define INF 2147483647

// 上N,下S,右E,左W。

//输入 
int n,m,k;
char a[1010][1010];
struct node1{
    int dir;int len;
}t[100010];


//b[i][j][k]表示点(i,j)往方向k最多可以走的步数。 
int b[1010][1010][4]; 

//字母点 
struct node{
    int x;int y;char g;
    bool operator<(node b)
    {
        return g < b.g;
    }
};
list <node> l; 
list <node>::iterator it;


int d[4][2] = {-1,0,1,0,0,1,0,-1};
 
//模拟q这个点走的过程 
bool can(node q) {
    int x = q.x;int y = q.y;
    for(int i = 0;i < k; i++){    
        node1 s = t[i];
        if(b[x][y][s.dir] < s.len) return false;
        x = x + d[s.dir][0]*s.len;
        y = y + d[s.dir][1]*s.len;
    }
    return true;
}
 
int main(){
    //输入数据 
    cin >> n >> m;
    node e;
    for(int i = 1;i <= n; i++) {
        for(int j = 1;j <= m; j++) {
            cin >> a[i][j];
            if(a[i][j] != '#' && a[i][j] != '.'){
                e.x = i; e.y = j; e.g = a[i][j];
                l.push_back(e);
            }
        }
    }
    //对子母点按字典序排序 
    l.sort();
     
    for(int j = 1;j <= m; j++){
        //预处理每个点最多能往北边走多少步 
        int num = 0;
        for(int i = 1;i <= n; i++){
            if(a[i][j] != '#'){
                b[i][j][0] = num;num++;
            }else{
                num = 0;
            }
        }
        //预处理每个点最多能往南边走多少步
        num = 0;
        for(int i = n; i >= 1; i--){
            if(a[i][j] != '#'){
                b[i][j][1] = num; num++;
            }else{
                num = 0;
            }
        }
    }
    
    for(int i = 1; i <= n; i++){
        //预处理每个点最多能往东边走多少步
        int num = 0;
        for(int j = 1;j <= m; j++){
            if(a[i][j] != '#'){
                b[i][j][3] = num; num++;
            }else{
                num = 0;
            }
        }
        //预处理每个点最多能往西边走多少步
        num = 0;
        for(int j = m; j >= 1; j--){
            if(a[i][j] != '#'){
                b[i][j][2] = num; num++;
            }else{
                num = 0;
            }
        }
    }
    
    //把字母方向转换成数字表示 
    cin >> k;
    char key;
    for(int i = 0;i < k; i++){
        cin >> key >> t[i].len;
        if(key == 'N') t[i].dir = 0;
        else if(key == 'S') t[i].dir = 1;
        else if(key == 'E') t[i].dir = 2;
        else if(key == 'W') t[i].dir = 3;
    }
    
    //对每个子母点进行模拟 
    bool flag = false;
    for(it = l.begin();it != l.end(); it++){
        node q = *it;
        if(can(q)){
            cout << q.g;
            flag = true;
        }
    }
    if(!flag) cout << "no solution";
    cout << endl;
    return 0;
} 
原文地址:https://www.cnblogs.com/zhangjiuding/p/7836698.html