uva 11882 C - Biggest Number 【最优性剪枝】【深搜】

题意:给定一个n*m的矩阵,'#'表示不能通过,每个方格只能走过一次且下一步只能走上下左右四个方向,问,能够组成最大连续的数字为多大?

思路:最优性剪枝即当前所搜索到的结点的后续最优情况也不比当前最优情况好,就停止对当前结点的搜索,回溯到其父亲结点,搜索其它情况。这里用到了两个剪枝,一个是当前已搜索到的数字长度+后续能搜索到的数字长度小于最优值时,直接剪枝;另一个是长度相等时,判断字典序大小,前者较小时,剪枝,这里需要注意,将后续能够搜索到的数字按从大到小的顺序存入当前数字之后,再和最优值进行比较。

结:这道题自己被坑的比较惨,错在:long long最多能存十进制的19位数,而此题最多为30位,故用long long必然存最优值必然错误;当字典序相等而当前数字+后续搜索到的数字大于等于最优值时,还要继续往下搜索,而不是返回父亲结点,else出错。第一次用string容器,头文件#include<string>,以后使用注意:s.clear()是清空,比较string大小时,保证长度相等才行

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue>
#include<string>
using namespace std;
const int maxn = 20;
char vis[maxn][maxn],str[maxn];
int book[maxn][maxn],used[maxn][maxn];
int n,m;
int k[4][2]={0,1,0,-1,1,0,-1,0};
string ans;
struct node{
	int x,y;
};
int find(int x,int y)
{
	if(x < 0||x >n-1||y<0||y>m-1)
		return 0;
	return 1;
}
int Judge(int x,int y)//查找能够到达的所有数字 
{
	int i,j,count,nx,ny;
	struct node nowq,nextq;
	queue<node>q;
	for(i = 0; i < n; i ++)
		for(j = 0; j < m; j ++)
			used[i][j] = book[i][j]; 
	count = 0;
	nowq.x = x;
	nowq.y = y;
	q.push(nowq);
	while(!q.empty())
	{
		nowq = q.front();
		q.pop();
		for(i = 0; i < 4; i ++)
		{
			nx = nowq.x + k[i][0];
			ny = nowq.y + k[i][1];
			if(find(nx,ny)&&!used[nx][ny]&&vis[nx][ny]!='#')
			{
				str[count ++] = vis[nx][ny];
				used[nx][ny] = 1;
				nextq.x = nx;
				nextq.y = ny;
				q.push(nextq);
			}
		}
	}
	str[count] = '\0';
	return count;
}
void dfs(int x,int y,string s)
{
	int nx,ny,i,j,length;
	length = Judge(x,y);
	if(s.length() > ans.length()||(s.length() == ans.length()&&s > ans))
		ans = s;//当前数字长度大于最优值or长度相等字典序更大时,更新最优值 
	if(length + s.length() < ans.length())
		return ;//如果当前长度+能够到达数字的长度小于最优长度,则剪枝 
	else if(length+s.length() == ans.length())//如果相等,则比较字典序 
	{
		sort(str,str+length);//将能够到达的值按升序排列 
		string ss = s;
		for(i = length-1; i >= 0; i --)
			ss += str[i];
		if(ss < ans)//如果字典序小于最优值,则剪枝 
			return;
	}
	for(i = 0; i < 4; i ++)
	{
		nx = x + k[i][0];
		ny = y + k[i][1];
		if(find(nx,ny)&&!book[nx][ny]&&vis[nx][ny]!='#')
		{
			book[nx][ny] = 1;
			dfs(nx,ny,s+vis[nx][ny]);
			book[nx][ny] = 0;
		}
	}

	return;
}
void Count()
{
	int i,j;
	string s;
	ans.clear();
	for(i = 0; i < n; i ++)
		for(j = 0; j < m; j ++)
			if(vis[i][j]!='#')
			{
				memset(book,0,sizeof(book));
				book[i][j] = 1;
				s.clear();
				dfs(i,j,s +vis[i][j]);
			}
	return;
}
int main()
{
	int i;
	while(scanf("%d%d",&n,&m),n!=0||m!=0)
	{
		for(i = 0; i < n; i ++)
			scanf("%s",vis[i]);
		Count();
		cout<<ans<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值