openjudge_2.5基本算法之搜索_156:LETTERS

题目

156:LETTERS
总时间限制: 1000ms 内存限制: 65536kB
描述
A single-player game is played on a rectangular board divided in R rows and C columns. There is a single uppercase letter (A-Z) written in every position in the board.
Before the begging of the game there is a figure in the upper-left corner of the board (first row, first column). In every move, a player can move the figure to the one of the adjacent positions (up, down,left or right). Only constraint is that a figure cannot visit a position marked with the same letter twice.
The goal of the game is to play as many moves as possible.
Write a program that will calculate the maximal number of positions in the board the figure can visit in a single game.
输入
The first line of the input contains two integers R and C, separated by a single blank character, 1 <= R, S <= 20.
The following R lines contain S characters each. Each line represents one row in the board.
输出
The first and only line of the output should contain the maximal number of position in the board the figure can visit.
样例输入
3 6
HFDFFB
AJHGDH
DGAGEH
样例输出
6

翻译

描述
单人游戏是在一个被分成R行和C列的矩形棋盘上进行的。在黑板的每个位置都有一个大写字母(a - z)。
在游戏开始前,在棋盘的左上角(第一行,第一列)有一个图形。在每次移动中,
玩家可以将图形移动到相邻的位置(上、下、左或右)。唯一的限制是,
一个图形不能访问用相同字母标记的位置两次。
这个游戏的目标是尽可能多走几步棋。
编写一个程序,计算图形在一个游戏中可以访问的最大位置数。
输入
输入的第一行包含两个整数R和C,由一个空白字符分隔,1 <= R, S <= 20。
下面的R行每行包含S个字符。每条线代表棋盘上的一行。
输出
输出的第一行和唯一一行应该包含图形可以访问的最大位置数。

理解

在这里插入图片描述
第一图是宽搜,从A出发(再不能去A了)可以到达B和C(不能再去B和C),于是再不能去别的地方了。
第二图是深搜,选择某条路走到低,不是最大就撤销上一步尝试别的方向,于是可以A到B到C到D到E到F,答案可以到达6处。
如果访问顺序对结果有影响,或者到达地有区别就用深搜。

代码

#include <bits/stdc++.h>
using namespace std;
int r,s,
ans,//到达的点数和
board[25][25],//每个位置的字母
d[4][2]={{0,-1},{-1,0},{0,1},{1,0}};//上下左右移动
bool k[26];//一个字母标记位置只能去一次
bool ok(int x,int y){
return x>=1&&x<=r&&y>=1&&y<=s&&!k[board[x][y]];//该字母标记位置只能去一次
}
void view(){
cout<<ans<<“观察\n”;
for(int i=1;i<=r;i++){
for(int j=1;j<=s;j++)cout<<char(board[i][j]+‘A’)<<“,”<<k[board[i][j]]<<“\t”;
cout<<endl;
}
}
void go(int xx,int yx,int n){//深搜
ans=max(ans,n);//不同方案值,找最大值
for(int i=0;i<4;i++){//四个方向
int x=xx+d[i][0],y=yx+d[i][1];
if(ok(x,y)){//在地图内,而且没有走过该字母标记位置
k[board[x][y]]=1;//标记该字母到过了
go(x,y,n+1);
k[board[x][y]]=0;//回溯,撤销上次移动
//view();
}
}
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>r>>s;
char c;
for(int i=1;i<=r;i++)
for(int j=1;j<=s;j++){
cin>>c;board[i][j]=c-‘A’;//大写字母转换成对应的数字
}
k[board[1][1]]=1;//不能再走出发位置字母
go(1,1,1); //深搜
cout<<ans;
return 0;
}

代码2

#include <bits/stdc++.h>
using namespace std;
struct point{
char c;
int x,y,cx,m;
bool v[26];
point(){
m=0;
memset(v,0,sizeof(v));
}
point(char cc,int xx,int yx){
memset(v,0,sizeof(v));
x=xx,y=yx,c=cc,m=0,cx=cc-‘A’;
v[cx]=1;
}
}p[101][101];
int v[26];
int h,w,maxn,
d[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
char c;
void view(point px){
cout<<px.x<<“,”<<px.y<<“:”<<px.c<<endl;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
cout<<p[i][j].c<<“,”<<p[i][j].m<<“:”;
//for(int vi=0;vi<26;vi++)cout<<(p[i][j].v[vi]?char(vi+‘A’):0);
cout<<“\t”;
}
cout<<endl;
}
}
void go(point px){
int x,y,cx;
maxn=max(maxn,px.m);
for(int i=0;i<4;i++){
x=px.x+d[i][0],y=px.y+d[i][1];
if(x<1||x>h||y<1||y>w||p[x][y].m||px.v[p[x][y].cx])continue;
p[x][y].m=px.m+1;
for(int i=0;i<26;i++)p[x][y].v[i]=px.v[i];
p[x][y].v[p[x][y].cx]=1;
go(p[x][y]);
p[x][y].m=0;
for(int i=0;i<26;i++)p[x][y].v[i]=0;
p[x][y].v[p[x][y].cx]=1;
}
//view(px);
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>h>>w;
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++){
cin>>c;
p[i][j]=point{c,i,j};
}
p[1][1].m=1;
go(p[1][1]);
cout<<maxn;
return 0;
}

小结

只有大写字母A-Z,可以改成对应的数字。
标记某位置,可以汇总到标记某字母。
可以一条线遍历所有该访问的地方
用数组表示哪个字母已经访问
访问的顺序不一样,结果不一样,用深搜

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值