题意:在一个R行C列(2=<R,C<=15,R*C<=30)的矩阵里有障碍物和数字格(包含1~9的数字)。你可以从任意一个数字格出发,每次沿上下左右的方向走一格,但不能走障碍格中,也不能重复经过,然后把沿途经过的所有数字连起来,问能得到的最大整数是多少?
分析:题目很简单,但容易超时,必须加上预期剪枝,就是当前搜索的和它之后可能搜索的最大长度加起来是否超过当前最优解,如果相等就按字典序比较,否则回溯。
# include<iostream>
# include<cstdio>
# include<cmath>
# include<map>
# include<queue>
# include<string>
# include<string.h>
#include<set>
#include<list>
# include<algorithm>
using namespace std;
char mp[30][30];
int row, col;
int vis[30][30];
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,1,-1 };
pair<int, int>que[100];
int head, tail;
int viss[30][30];
string res;
int h(int x,int y) {
head=tail = 0;
int cnt = 0;
que[tail++] = make_pair(x, y);
memcpy(viss, vis, sizeof(viss));
while (head < tail) {
pair<int, int>u = que[head++];
for (int i = 0; i < 4; i++) {
int ddx = u.first + dx[i];
int ddy = u.second + dy[i];
if (ddx < 0 || ddx >= row || ddy < 0 || ddy >= col)continue;
if (!viss[ddx][ddy]&&mp[ddx][ddy]!='#') {
viss[ddx][ddy] = 1;
cnt++;//还能搜索的长度
que[tail++] = make_pair(ddx, ddy);
}
}
}
return cnt;
}
void dfs(int curx,int cury,int layer,string A) {
int ant = h(curx, cury);
int l = res.size();
if (layer + ant < l)return;//期望剪枝
if (layer + ant == l) {
if (A + "z" < res)return;//字典序剪枝
}
if (A.size() > res.size() || (A.size() == res.size() && res < A))res = A;//更新结果
for (int i = 0; i < 4; i++) {
int ddx = curx + dx[i];
int ddy = cury + dy[i];
if (ddx < 0 || ddx >= row || ddy < 0 || ddy >= col)continue;
if (vis[ddx][ddy]||mp[ddx][ddy]=='#')continue;
vis[ddx][ddy] = 1;
dfs(ddx, ddy, layer + 1, A+mp[ddx][ddy]);
vis[ddx][ddy] = 0;
}
}
int main() {
while (cin >> row >> col && row&&col) {
for (int i = 0; i < row; i++)cin >> mp[i];
memset(vis, 0, sizeof(vis));
res = "";
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (mp[i][j]!='#') {
string A="";
A+=mp[i][j];
vis[i][j] = 1;
dfs(i, j, 1, A);
vis[i][j] = 0;
}
}
}
cout << res << endl;
}
return 0;
}