UVALive 5966 Blade and Sword -- 搜索(中等题)

题意:给一幅地图,P为起点,D为终点,‘*‘为传送阵,到达传送阵可以传到任意一个其他的传送阵,传到以后可以正常走或者再传回来,问P->D最短步数。

分析:这题一定要细心,分析要到位才能搞定,错一点都WA。有两种思路:

1.走到一个传送点之后,将所有能传到的地方都加入队列,然后清除传送阵向量(vector),因为以后不用再互相传了,对于某个传送阵k,以后从别的点传到k的效果还不如从这个点传到k,所以清空传送阵,又因为其他传送阵可以传回来,此时传送阵向量要把当前传送阵push_back进去,以便其他点传过来,每个传送点设一个标记,flag=0说明这个传送点还没用过,flag=1说明这个传送点是被传过来的,还可以传一次,use[][]数组记录某个传送点被用过没有(即通过它传出去过没有),然后搞即可。

代码:(63ms, 0KB)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 1000017

char ss[205][205];
bool vis[205][205],use[205][205];
int n,m,step;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
struct node
{
    int x,y,tag;
    node(int _x,int _y,int _tag)
    {
        x = _x;
        y = _y;
        tag = _tag;
    }
    node(){}
}P,D;
vector<node> trans;

bool OK(int nx,int ny)
{
    if(nx >= 0 && nx < n && ny >= 0 && ny < m)
        return 1;
    return 0;
}

bool bfs()
{
    queue<node> que;
    memset(vis,0,sizeof(vis));
    memset(use,0,sizeof(use));
    que.push(P);
    int i,j,k;
    vis[P.x][P.y] = 1;
    while(!que.empty())
    {
        int SIZE = que.size();
        while(SIZE--)
        {
            node tmp = que.front();
            que.pop();
            int nx = tmp.x;
            int ny = tmp.y;
            if(nx == D.x && ny == D.y)
                return 1;
            if(ss[nx][ny] == ‘*‘)   //tag = 1 : 被传过来的,tag = 0 : 传出去
            {
                if(tmp.tag == 0 || (tmp.tag==1 && !use[nx][ny]))
                {
                    for(i=0;i<trans.size();i++)
                    {
                        int x = trans[i].x;
                        int y = trans[i].y;
                        if(vis[x][y] || (nx == x && ny == y))
                            continue;
                        trans[i].tag = 1;
                        que.push(trans[i]);
                    }
                    trans.clear();
                    trans.push_back(tmp);  //这个点还可以被传回来
                    if(tmp.tag == 1)   //被传过来并且没用过的,现在用过了
                        vis[nx][ny] = 1;
                    use[nx][ny] = 1;
                }
                if(tmp.tag == 1)   //被传,用过了,就当做普通点好了  别用else if
                {
                    for(k=0;k<4;k++)
                    {
                        int kx = nx + dx[k];
                        int ky = ny + dy[k];
                        if(!OK(kx,ky) || ss[kx][ky] == ‘#‘ || ss[kx][ky] == ‘*‘ || vis[kx][ky])
                            continue;
                        vis[kx][ky] = 1;
                        que.push(node(kx,ky,0));
                    }
                    vis[nx][ny] = 1;
                }
            }
            else   //普通点,普通走法
            {
                for(k=0;k<4;k++)
                {
                    int kx = nx + dx[k];
                    int ky = ny + dy[k];
                    if(!OK(kx,ky) || ss[kx][ky] == ‘#‘ || vis[kx][ky])
                        continue;
                    if(ss[kx][ky] != ‘*‘ )  //如果是‘*‘,则不能确定
                        vis[kx][ky] = 1;
                    que.push(node(kx,ky,0));
                }
            }
        }
        step++;
    }
    return 0;
}

int main()
{
    int t,cs = 1,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        trans.clear();
        for(i=0;i<n;i++)
        {
            scanf("%s",ss[i]);
            for(j=0;j<m;j++)
            {
                if(ss[i][j] == ‘*‘)
                    trans.push_back(node(i,j,0));
                else if(ss[i][j] == ‘P‘)
                    P = node(i,j,0);
                else if(ss[i][j] == ‘D‘)
                    D = node(i,j,0);
            }
        }
        step = 0;
        if(bfs())
            printf("Case %d: %d\n",cs++,step);
        else
            printf("Case %d: impossible\n",cs++);
    }
    return 0;
}

2.统计传送点的数量,如果只有一个传送点,那么不能经过传送点到达,只能走普通路到终点。否则,先走一遍普通路ans = bfs(),再从P搜一个与他最近的传送点,从D搜一个与它最近的传送点,判断这两个传送点是不是同一个,如果是只能再通过图中另一个传送点作为终中继,此时ans = bfsP()+bfsD()+2,不是同一个那就更好处理了,ans = bfsP+bfsD+1。细节问题看代码吧。

代码:(22ms, 0KB)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 1000017

struct node
{
    int x,y,step;
}P,D;

int n,m;
int cnt1,cnt2;
char ss[205][205];
int vis[205][205];
queue<node> que;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int X1,X2,Y1,Y2;

int OK(int nx,int ny)
{
    if(nx >= 0 && nx < n && ny >= 0 && ny < m && ss[nx][ny] == ‘.‘)
        return 1;
    return 0;
}

int bfsPD()
{
    while(!que.empty())
        que.pop();
    P.step = 0;
    memset(vis,0,sizeof(vis));
    que.push(P);
    vis[P.x][P.y] = 1;
    while(!que.empty())
    {
        node now = que.front();
        que.pop();
        int nx = now.x;
        int ny = now.y;
        int step = now.step;
        for(int k=0;k<4;k++)
        {
            int kx = nx + dx[k];
            int ky = ny + dy[k];
            if(ss[kx][ky] == ‘D‘)
                return step+1;
            if(!OK(kx,ky) || vis[kx][ky])  //不考虑‘*‘
                continue;
            node tmp;
            tmp.x = kx;
            tmp.y = ky;
            tmp.step = step + 1;
            vis[kx][ky] = 1;
            que.push(tmp);
        }
    }
    return Mod;
}

int bfsP()    //从P找‘*‘
{
    int dis = Mod;
    while(!que.empty())
        que.pop();
    memset(vis,0,sizeof(vis));
    P.step = 0;
    que.push(P);
    vis[P.x][P.y] = 1;
    while(!que.empty())
    {
        node now = que.front();
        que.pop();
        int nx = now.x;
        int ny = now.y;
        int step = now.step;
        if(step >= dis)
            return dis;
        for(int k=0;k<4;k++)
        {
            int kx = nx + dx[k];
            int ky = ny + dy[k];
            if(ss[kx][ky] == ‘*‘)
            {
                X1 = kx;
                Y1 = ky;
                cnt1++;
                dis = step + 1;
            }
            else if(OK(kx,ky))
            {
                if(!vis[kx][ky])
                {
                    node tmp;
                    tmp.x = kx;
                    tmp.y = ky;
                    tmp.step = step+1;
                    vis[kx][ky] = 1;
                    que.push(tmp);
                }
            }
        }
    }
    return dis;
}

int bfsD()    //从D找‘*‘
{
    int dis = Mod;
    while(!que.empty())
        que.pop();
    memset(vis,0,sizeof(vis));
    D.step = 0;
    que.push(D);
    vis[D.x][D.y] = 1;
    while(!que.empty())
    {
        node now = que.front();
        que.pop();
        int nx = now.x;
        int ny = now.y;
        int step = now.step;
        if(step >= dis)
            return dis;
        for(int k=0;k<4;k++)
        {
            int kx = nx + dx[k];
            int ky = ny + dy[k];
            if(ss[kx][ky] == ‘*‘)
            {
                X2 = kx;
                Y2 = ky;
                cnt2++;
                dis = step + 1;
            }
            else if(OK(kx,ky))
            {
                if(!vis[kx][ky])
                {
                    node tmp;
                    tmp.x = kx;
                    tmp.y = ky;
                    tmp.step = step+1;
                    vis[kx][ky] = 1;
                    que.push(tmp);
                }
            }
        }
    }
    return dis;
}

int main()
{
    int t,cs = 1,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int cnt = 0;
        for(i=0;i<n;i++)
        {
            scanf("%s",ss[i]);
            for(j=0;j<m;j++)
            {
                if(ss[i][j] == ‘P‘)
                    P.x = i,P.y = j;
                else if(ss[i][j] == ‘D‘)
                    D.x = i,D.y = j;
                else if(ss[i][j] == ‘*‘)
                    cnt++;
            }
        }
        int ans = 0;
        cnt1 = cnt2 = 0;
        if(cnt <= 1)    //少于等于1个传送点,就只能按普通路走过去
            ans = bfsPD();
        else
        {
            int d1,d2;
            ans = bfsPD();
            d1 = bfsP();
            d2 = bfsD();
            if(cnt1 == cnt2 && cnt1 == 1)  //周围都只有一个点,通过这两个点中介
            {
                if(X1 == X2 && Y1 == Y2)  //是同一个点,因为至少还有一个点,所以可以传回来
                    ans = min(ans,d1+d2+2);
                else
                    ans = min(ans,d1+d2+1);
            }
            else  //有不止一个点,可以用不同点传
                ans = min(ans,d1+d2+1);
        }
        if(ans >= Mod)
            printf("Case %d: impossible\n",cs++);
        else
            printf("Case %d: %d\n",cs++,ans);
    }
    return 0;
}

Written by Whatbeg

UVALive 5966 Blade and Sword -- 搜索(中等题)

时间: 2024-08-01 14:47:44

UVALive 5966 Blade and Sword -- 搜索(中等题)的相关文章

POJ 1979 Red and Black 深度优先搜索上手题

Red and Black Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21738   Accepted: 11656 Description There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a

UVALive 6470 Chomp --记忆化搜索

题意:给一个只有三行的方块阵(横向最多100个),然后p,q,r分别代表第1,2,3层的方格数,两人轮流去掉一个格子,此时这个格子的右上方都会被去掉,面临只剩最左下角的一个格子的状态的人输,问先手能否赢,要赢得话应该取哪个方格. 解法:记忆化搜索,设dp[p][q][r]表示第1,2,3层方格数分别为p,q,r的输赢状态,0为输,1为赢,X[][][],Y[][][]分别表示其该取的方格坐标.每次求dp[p][q][r]时,枚举能达到的状态,如果这些状态的输赢值有一个为输,则此状态一定为赢,返回

华为题 搜索水题 DFS

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <string> 6 #include <iterator> 7 #include <algorithm> 8 #include <cstdlib> 9 #include <deque> 10 #include &l

lintcode 中等题:search a 2d matrix II 搜索二维矩阵II

题目 搜索二维矩阵 II 写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数. 这个矩阵具有以下特性: 每行中的整数从左到右是排序的. 每一列的整数从上到下是排序的. 在每一行或每一列中没有重复的整数. 样例 考虑下列矩阵: [     [1, 3, 5, 7],     [2, 4, 7, 8],     [3, 5, 9, 10] ] 给出target = 3,返回 2 挑战 要求O(m+n) 时间复杂度和O(1) 额外空间 解题 直接遍历,时间复杂度是O(MN) public

lintcode 中等题:word search 单词搜索

题目 单词搜索 给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词. 单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻.每个单元中的字母最多只能使用一次. 样例 给出board = [ "ABCE", "SFCS", "ADEE" ] word = "ABCCED", ->返回 true, word = "SEE",-> 返回 true, word = 

HDU 1142 A Walk Through the Forest (Dijkstra + 记忆化搜索 好题)

A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6350    Accepted Submission(s): 2332 Problem Description Jimmy experiences a lot of stress at work these days, especial

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

搜索基础题

1.http://acm.hdu.edu.cn/showproblem.php?pid=1312 题意:在一个仅有红黑格子组成的矩形中,一个人只能走上下左右相邻黑色格子,问从起点开始共能走多少个格子? ’#‘:红色格子 ’.': 黑色格子: ’@‘:起点 BFS 和 DFS 都可以遍历所有走的点,每次走过一点时,计数++即可: 2.http://acm.hdu.edu.cn/showproblem.php?pid=1728 由题可知,在限制转弯数量的前提下 能够从一点走到另一个点即可:BFS 和

搜索刷题记录

我好菜啊!连暴搜都不会! 注意边界退出! 特开此帖,记录搜索学习之路!(逃) 1.全排列 2.八皇后 3.数的划分 由于此题有同一划分方法算一个的限制,我们为了避免搜多,可以使搜出的结果满足单调不降性,那么就要在dfs时传一个pre参数. 由于要使划分后数之和为n,记录当前搜的总值sum. 由于有划分k个的限制,记录当前搜出了几个. 小总结,dfs函数的参数由其限制条件得出. 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9368382.htm