码迷,mamicode.com
首页 > 其他好文 > 详细

【非经典】仙岛求药(二)

时间:2016-07-22 22:55:11      阅读:488      评论:0      收藏:0      [点我收藏+]

标签:

仙岛求药(二)

【试题描述】

    咳,上回说到李逍遥去求药,其实他找到药之后,还需要给他的婶婶送过去,所以他需要在最短的时间内找到要并且到达婶婶(‘s‘)所在的位置。

 

【输入要求】

    输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于100。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义: 
1) ‘@’:少年李逍遥所在的位置;
2) ‘.’:可以安全通行的方格;
3) ‘#’:有怪物的方格;
4) ‘*’:仙药所在位置。
5) ‘s‘ : 婶婶所在的位置。
    当在一行中读入的是两个零时,表示输入结束。 

 

【输出要求】

    对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药并且送给婶婶需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。 

 

【输入实例】

8 8
.@##...#
#....#.#
#.#.##..
*.#.###.
#.#...#.
..###*#.
...#.s..
.#.*.###
0 0 

  

【输出实例】

10

 

【其他说明】

 

【试题分析】

    仔细一看,可以瞬间想到:遍历到每个仙药再回到婶婶,求最小值,那么只需要这么写:

#include<iostream>
#include<cstring>
using namespace std;
char map[101][101];
int a[101][101],ans=0,m,n;
void res(int u,int v,int i,int j)
{
    int t=a[u][v];
    if(u==i&&v==j) ans=t;
    t++;
    if(v<m-1&&map[u][v+1]!=‘#‘&&a[u][v+1]>t)
    {
        a[u][v+1]=t;
        res(u,v+1,i,j);
    }
    if(u>0&&map[u-1][v]!=‘#‘&&a[u-1][v]>t)
    {
        a[u-1][v]=t;
        res(u-1,v,i,j);
    }
    if(v>0&&map[u][v-1]!=‘#‘&&a[u][v-1]>t)
    {
        a[u][v-1]=t;
        res(u,v-1,i,j);
    }
    if(u<n-1&&map[u+1][v]!=‘#‘&&a[u+1][v]>t)
    {
        a[u+1][v]=t;
        res(u+1,v,i,j);
    }
}
int startx,starty,endx[10000],endy[10000],k=0,ans1=9999999,endx2,endy2,k2=0,ans2=9999999,sx,sy,ans3=9999999;
int main() 
{
    while(scanf("%d%d",&n,&m)&&m!=0&&n!=0)
    {
        memset(a,1,sizeof(a));
        memset(endx,0,sizeof(endx));
        memset(endy,0,sizeof(endy));
        for(int i=0;i<n;i++) 
        {
            for(int j=0;j<m;j++)
            {
                scanf("%c",&map[i][j]);
                if(map[i][j]==‘@‘)
                {
                    startx=i;
                    starty=j;
                }
                if(map[i][j]==‘*‘)
			    {
                    endx[k]=i;
                    endy[k++]=j;
                }
                if(map[i][j]==‘s‘)
                {
                    endx2=i;
                    endy2=j;
                }
            }
            getchar();
        }
        memset(a,1,sizeof(a));
        a[startx][starty]=0;
        for(int i=0;i<k;i++)//枚举
        {
            memset(a,1,sizeof(a));//分段考虑
            a[startx][starty]=0;
            res(startx,starty,endx[i],endy[i]);
            ans1=ans,sx=endx[i],sy=endy[i];//赋值
            ans=0;
            memset(a,1,sizeof(a));
            a[sx][sy]=0;
            res(sx,sy,endx2,endy2);
            ans2=ans;
            if(ans3>ans2+ans1) ans3=ans1+ans2//更新;
            ans=0;
        }
        if(ans3<9999999)cout<<ans3<<endl;
        else cout<<-1;
        ans3=9999999;//更新
        ans1=9999999;
        ans2=9999999;
        k2=0;
        k=0;
    }
}

好了,写完代码了。

 

如果你认为对了,那么可以输入这组数据试一试

20 50

@*************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
**************************************************
*************************************************s

    按这样来说,每一个*都要被算一次,这样的复杂度即使是喜欢打暴力的人也是不能容忍的,当然,改进算法才是我们的重点,但是怎样优化呢?

    用BFS???

    不好吧,那也会超限,但是正解+BFS是很快的。

    用DFS???

    更差了……

 

    我们先来想一想这样一个问题,如果一个人要从上海开车去北京旅游,他会把所有路都傻傻的走一遍吗?当然不会了,因为人类有一张王牌——地图,我们可以去估一估最短距离。

    那么这道题也是一样的,我们可以大概估一个两点之间最短距离值,算出它以后,因为我们默认为两点之间没有障碍,所以它就是最短路了,如果这样算的话还是大于等于原来我们记录的那个最小值,那实际的路径一定比这个估算最优值大或等于,由此,我们可以去除多个药的枚举,就像人人皆知的KMP算法一样,这种算法名叫启发式搜索,是人工智能的一个知识点,不一定要将它完全地写出代码,但至少要了解并会使用。

    我们的代码只需要加上这么一行,就能大幅度提高效率(往往算法的精髓就在于此):

if(abs(endx[i]+endy[i]-startx-starty)+abs(endx2+endy2-endx[i]-endy[i])<ans3)

 

【代码】

#include<iostream>
#include<cstring>
using namespace std;
char map[101][101];
int a[101][101],ans=0,m,n;
void res(int u,int v,int i,int j)
{
    int t=a[u][v];
    if(u==i&&v==j) ans=t;
    t++;
    if(v<m-1&&map[u][v+1]!=‘#‘&&a[u][v+1]>t)
    {
        a[u][v+1]=t;
        res(u,v+1,i,j);
    }
    if(u>0&&map[u-1][v]!=‘#‘&&a[u-1][v]>t)
    {
        a[u-1][v]=t;
        res(u-1,v,i,j);
    }
    if(v>0&&map[u][v-1]!=‘#‘&&a[u][v-1]>t)
    {
        a[u][v-1]=t;
        res(u,v-1,i,j);
    }
    if(u<n-1&&map[u+1][v]!=‘#‘&&a[u+1][v]>t)
    {
        a[u+1][v]=t;
        res(u+1,v,i,j);
    }
}
int startx,starty,endx[10000],endy[10000],k=0,ans1=9999999,endx2,endy2,k2=0,ans2=9999999,sx,sy,ans3=9999999;
int main() 
{
    while(cin>>n>>m&&m!=0&&n!=0)
    {
        memset(a,1,sizeof(a));
        memset(endx,0,sizeof(endx));
        memset(endy,0,sizeof(endy));
        for(int i=0;i<n;i++) 
        {
            for(int j=0;j<m;j++)
            {
                cin>>map[i][j];
                if(map[i][j]==‘@‘)
                {
                    startx=i;
                    starty=j;
                }
                if(map[i][j]==‘*‘)
			    {
                    endx[k]=i;
                    endy[k++]=j;
                }
                if(map[i][j]==‘s‘)
                {
                    endx2=i;
                    endy2=j;
                }
            }
        }
        memset(a,1,sizeof(a));
        a[startx][starty]=0;
        for(int i=0;i<k;i++)
        {
            if(abs(endx[i]+endy[i]-startx-starty)+abs(endx2+endy2-endx[i]-endy[i])<ans3)
//判定,如果此代码其它地方不理解可以去看仙岛求药(一) { memset(a,1,sizeof(a)); a[startx][starty]=0; res(startx,starty,endx[i],endy[i]); ans1=ans,sx=endx[i],sy=endy[i]; ans=0; memset(a,1,sizeof(a)); a[sx][sy]=0; res(sx,sy,endx2,endy2); ans2=ans; if(ans3>ans2+ans1) ans3=ans1+ans2; ans=0; } } cout<<ans3<<endl; ans3=9999999; ans1=9999999; ans2=9999999; k2=0; k=0; } }

【非经典】仙岛求药(二)

标签:

原文地址:http://www.cnblogs.com/wxjor/p/5697428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!