2.1 “穷竭搜索”例题

A. HDU 1035 Robot Motion

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1035
(链接被吃,复制到浏览器打开)

基础的地图性dfs.

思路: 先按照地图顺序dfs遍历图,用数组存储当前位置被访问的次数和步数,然后判断找到出口或找到一个点 x 被访问第二次时跳出。若构成循环,x 第一次被访问时的步数减一就是循环前走的步数(now), 所有的点(step)减去循环前走的步数 (now) 就是循环中点的个数。

AC代码:

/*HDU 1035*/
#include<bits/stdc++.h>
using namespace std;
char mapp[15][15];
int vis[15][15][2];  //vis[][][0]储存他被访问过多少次   vis[][][1]储存它当前的步数
int n,m,st;
int flag;
int step;
int now;
void dfs(int x,int y)
{
   
    if(x<0 || y<0 || x>=n || y>=m) //如果超出边界表示已经找到出口 就输出返回
    {
   
        cout<<step<<" step(s) to exit"<<endl;
        return ;
    }
    else if(vis[x][y][0]==1)  //当该点等于1(被访问过)
    {
   
        now=vis[x][y][1]-1;//达成循环一共有 step 个点 (步)  ,到达循环前的点就有  now=vis[x][y][1]-1 个
        cout<<now<<" step(s) before a loop of "<<step-now<<" step(s)"<<endl;//step-now 就是循环个点的个数
        return;
    }
    else
    {
   
        vis[x][y][0]++;  // 访问一次就++
        step++;//步数++;
        vis[x][y][1]=step; //vis[][][1]储存当前步数
    }

    if(mapp[x][y]=='N') dfs(x-1,y);
    else if(mapp[x][y]=='S') dfs(x+1,y);
    else if(mapp[x][y]=='E') dfs(x,y+1);
    else dfs(x,y-1);
}
int main()
{
   
    while(cin>>n>>m>>st && st && n && m)
    {
   

        flag=now=0;
        step=0;
        memset(mapp,'0',sizeof(mapp));
        memset(vis,0,sizeof(vis));
        for(int i=0; i<n; i++)
        {
   
                cin>>mapp[i];
        }
        dfs(0,st-1);//数组从0开始存储  起始位置就是(0,st-1)
    }
    return 0;
}

B. OpenJ_Bailian 2748 全排列

传送门:http://bailian.openjudge.cn/practice/2748?lang=en_US

数据型dfs,遍历结束后回溯一下就ok

思路: 输入一个字符串,然后按字典序给字符串排序,挨个对每个字符深搜,把搜索到字符存储到一个数组里。深搜过程中标记访问,深搜结束后回溯。

PS: 有小伙伴直接调用STL里面 next_permutation 函数,也可以解决这道题,但是全排列裸题很少有,不建议这样写。
AC代码:

/*OpenJ_Bailian 2748*/
#include<bits/stdc++.h>
using namespace std;
char s[10];
int num=0;
char mapp[10];
int vis[10];
void dfs(char a)
{
   
	if(num==strlen(s)-1 ) //如果num与s的长度相等 表示搜索到头了 
	{
   
		for(int i=0; i<=num; i++)// 遍历输出mapp数组然后返回
		{
   
			cout<<mapp[i];
		}
		putchar(10);//输出回车
		return;
	}
	for(int i=0; i<strlen(s); i++) // i 从0开始按字典序对下一个字符进行深搜
	{
   
		if(vis[i]==0)//如果s[i]没有被访问过就对是s[i]深搜
		{
   
			num++;
			vis[i]=1;//标记已访问
			mapp[num]=s[i]; //访问后把s[i]存储在mapp里
			dfs(s[i]);//对s[i]深搜
			vis[i]=0;//回溯
			num--;//同上
		}
	}
}
int main()
{
   
	while(cin>>s)
	{
   
		sort(s,s+strlen(s)); //从小到大给数组s排序
		for(int i=0; i<strlen(s); i++) // 按字典序挨个对s[i]深搜
		{
   
			num=0;// num存储是当前第几个数据
			mapp[0]=s[i]; //把深搜出来的字符存到mapp数组里
			vis[i]=1; //遍历后标记被访问过
			dfs(s[i]);//对s[i]深搜】

			memset(vis,0,sizeof(vis)); //深搜结束后把vis 和 mapp 清空
			memset(mapp,'0',sizeof(mapp));

		}
	}
	return 0;
}

C. HDU 1010 Tempter of the Bone

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1010

dfs+奇偶剪枝+回溯

思路:常规的dfs题型写法,需要注意剪枝。第一步剪枝就是判断全都是路的情况给的时间都小于最短到达的时间,就不用搜索判断一下直接输出;第二步奇偶剪枝比较难发现,搜索过程中剩余时间(t-step)减去到达终点的所需时间为奇数时就不可能到达终点。

AC代码:

/*HDU 1010*/
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define mem(a) memset(a,0,sizeof(a));
int n,m,t;
char mapp[10][10];
int fx[4]= {
   0,0,1,-1};
int fy[4]= {
   1,-1,0,0};
int sx,sy;//起点
int ex,ey;//终点
int flag;
void dfs(int x,int y,int step)
{
   
    if(x==ex&&y==ey && step==t)//如果(x,y)是终点,并且到达时间刚好等于时间t 表示可以逃出迷宫
    {
   
        flag=1;
        return ;
    }

    int p = (t-step)-(abs(x-ex)+abs(y-ey)); //当前剩余时间(t-step)减去到达终点最短需要的时间
    if(p<0 || p&1) //第二步剪枝:如果p<0 不能走出迷宫 或者 p为奇数 也不能走出迷宫 直接return 
        return ;

    for(int i=0; i<4; i++)
    {
   
        int dx=x+fx[i];
        int dy=y+fy[i];
        if(dx>=0 && dx<n && dy>=0 && dy<m && mapp[dx][dy]!='X')
        {
   
            mapp[dx][dy]='X';//走过的路都修改为墙
            dfs(dx,dy,step+1);//对当前位置进行深搜 步数 +1
            mapp[dx][dy]='.';//回溯
        }
    }
    return 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值