題意:在一個R行C列
(2≤R,C≤15,R∗C≤30) 的矩陣裏有障礙物和數字格(包含1~9的數字)。你可以從任意一個數字格出發,每次沿着上下左右之一的方向走一格,但不能走到障礙格中,也不能重複經過一個數字格,然後把沿途經過的所有數字連起來,如圖所示。如圖可以得到9784,4832145等整數。問:能得到的最大整數是多少?(本段摘自《算法競賽入門經典(第2版)》)
分析:
枚舉起點進行DFS即可。有一個最優性剪枝,即噹噹前位置的時候,剩下可以走的最大長度加上已走長度如果仍然小於當前最優的答案時,直接return,如果相等但是字典序比當前最優答案小的話也直接return。
代碼:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>
using namespace std;
const int maxn = 20 + 5;
const int dx[] = {0, 0, -1, 1}, dy[] = {1, -1, 0, 0};
struct Node
{
int x, y;
};
int r, c;
char a[maxn][maxn];
int v[maxn][maxn], vv[maxn][maxn];
string ans, tmp;
Node q[maxn * maxn];
void update(const string& s)
{
int l1 = ans.size(), l2 = s.size();
if ((l1 < l2) || (l1 == l2 && s > ans))
ans = s;
}
int h(int x, int y)
{
int head = 0, tail = 0, cnt = 0;
q[tail].x = x;
q[tail++].y = y;
memcpy(vv, v, sizeof(v));
while (head != tail)
{
for (int i = 0; i < 4; ++i)
{
int xx = q[head].x + dx[i], yy = q[head].y + dy[i];
if (xx >= 0 && xx < r && yy >= 0 && yy < c && a[xx][yy] != '#' && !vv[xx][yy])
{
q[tail].x = xx;
q[tail++].y = yy;
++cnt;
vv[xx][yy] = 1;
}
}
++head;
}
return cnt;
}
void DFS(int x, int y, string s, int deep)
{
int l = h(x, y);
if (l + deep < ans.size())
return;
if (l + deep == ans.size() && (s + "z") < ans)
return;
update(s);
for (int i = 0; i < 4; ++i)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 0 && xx < r && yy >= 0 && yy < c && a[xx][yy] != '#' && !v[xx][yy])
{
v[xx][yy] = 1;
DFS(xx, yy, s + a[xx][yy], deep + 1);
v[xx][yy] = 0;
}
}
}
int main()
{
while (~scanf("%d%d", &r, &c), r || c)
{
ans = "";
for (int i = 0; i < r; ++i)
scanf("%s", a[i]);
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
if (a[i][j] != '#')
{
memset(v, 0, sizeof(v));
v[i][j] = 1;
tmp = "";
tmp += a[i][j];
DFS(i, j, tmp, 1);
}
cout << ans << '\n';
}
return 0;
}