原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078
题解:刚开始做的时候,没有思路,因为第一次接触dfs函数含有双重循环,觉得自己写下去肯定超时,所以网上看了看其它人的答案,原来用到记忆化搜索,顺便学习了一下,就是保存每个子问题的解,类似动态规划。
参考博客:http://blog.csdn.net/hurmishine/article/details/51240499
这个博客中提到的方法用的其实是倒推的意思,就是一直深搜到最大的点,然后倒着来依次记录走每个方向的最大的值。
代码如下:
这个代码比较好理解,与普通的dfs在格式是一样的。
#include
#include
using namespace std;
int init[102][102];
int ans[102][102];
int dis[4][2] = { 0,1,1,0,0,-1,-1,0 };
int n, k;
bool OK(int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= n)
return false;
return true;
}
int dfs(int x, int y) {
int answer = 0;
if (ans[x][y])
return ans[x][y];
for (int i = 0;i < 4;i++)
for (int j = 1;j <= k;j++) {
int xx = x + dis[i][0] * j;
int yy = y + dis[i][1] * j;
if (OK(xx, yy) && init[xx][yy]>init[x][y])
answer = max(answer, dfs(xx, yy));
}
ans[x][y] = answer + init[x][y];
return ans[x][y];
}
int main() {
while (cin >> n >> k&&n != -1 && k != -1) {
memset(ans, 0, sizeof(ans));
for (int i = 0;i < n;i++)
for (int j = 0;j < n;j++)
cin >> init[i][j];
cout << dfs(0, 0) << endl;
}
}
还有另一种变形:
#include
#include
#include
#include
using namespace std;
int n, k, dp[101][101], mapp[101][101];
int dfs(int a, int b)
{
if (dp[a][b]) return dp[a][b];
dp[a][b] = mapp[a][b];
for (int i = 1; i <= k; i++)
{
if (a + ia + i][b]>mapp[a][b])
dp[a][b] = max(dp[a][b], dfs(a + i, b) + mapp[a][b]);
if (a - i >= 0 && mapp[a - i][b]>mapp[a][b])
dp[a][b] = max(dp[a][b], dfs(a - i, b) + mapp[a][b]);
if (b - i >= 0 && mapp[a][b - i]>mapp[a][b])
dp[a][b] = max(dp[a][b], dfs(a, b - i) + mapp[a][b]);
if (b + ia][b + i]>mapp[a][b])
dp[a][b] = max(dp[a][b], dfs(a, b + i) + mapp[a][b]);
}
return dp[a][b];
}
int main(void)
{
while (cin >> n >> k&&n != -1 && k != -1) {
memset(dp, 0, sizeof(dp));
for (int i = 0;i < n;i++)
for (int j = 0;j < n;j++)
cin >> mapp[i][j];
cout << dfs(0, 0) << endl;
}
}
另一种是排序后深搜(同样是丛最大到最小):
这种我感觉耗时时间长,重复计算了好多,比如如果(0,0)位置不是最小值。
#include
#include
#include
#include
#include
#define N 11000
using namespace std;
struct node
{
int c, num;
}b[N];
bool cmp(node a, node b)
{
return a.cint n, k, d[N], a[N];
int main()
{
while (~scanf("%d%d", &n, &k) && !(n == -1 && k == -1))
{
memset(d, 0, sizeof(d));
for (int i = 0;iscanf("%d", &a[i]);
d[i] = b[i].c = a[i];
b[i].num = i;
}
sort(b, b + n*n, cmp);
for (int i = n*n - 1;i >= 0;i--)
{
for (int j = -k;j <= k;j++)
{
if (j == 0) continue;
int tp = b[i].num;
int x = tp / n, y = tp%n;
int t1 = (x + j)*n + y, t2 = x*n + y + j;
if (x + j >= 0 && x + ja[tp])
d[tp] = max(d[tp], d[t1] + a[tp]);
if (y + j >= 0 && y + ja[tp])
d[tp] = max(d[tp], d[t2] + a[tp]);
}
}
cout << d[0] << endl;
}
}
另一种也是排序后深搜,但是这种是找到(0,0)的值在排序后的位置,然后从这个值开始到最大值,这种复杂度最低。
#include
#include
using namespace std;
struct Node {
int num;
int val;
};
Node a[11000];
int dp[11000],b[11000],seq[11000];
int n, k;
bool cmp(Node x, Node y) {
return x.val < y.val;
}
int main() {
while (cin >> n >> k&&n != -1 && k != -1) {
for (int i = 0;i < n*n;i++) {
cin >> a[i].val;
b[i] = a[i].val;
a[i].num = i;
}
memset(dp, -1, sizeof(dp));
sort(a, a + n*n, cmp);
for (int i = 0;i < n*n;i++)
seq[a[i].num] = i;
int flag;
for (int i = 0;i < n*n;i++)
if (a[i].num == 0)
flag = i;
int pos = flag;
dp[pos] = a[flag].val;
int ans = dp[pos];
for (int i = pos;i < n*n;i++) {
if (dp[i] == -1) continue;
int num = a[i].num;
int x = num / n;
int y = num%n;
for (int j = x - k;j <= x + k;j++) {
if (j < 0 || j >= n) continue;
int xx = j*n + y;
if (b[xx] <= b[num]) continue;
if (dp[i] + b[xx]>dp[seq[xx]]) {
dp[seq[xx]] = dp[i] + b[xx];
ans = max(ans, dp[seq[xx]]);
}
}
for (int j = y - k;j <= y + k;j++) {
if (j < 0 || j >= n) continue;
int xx = x*n + j;
if (b[xx] <= b[num]) continue;
if (dp[i] + b[xx]>dp[seq[xx]]) {
dp[seq[xx]] = dp[i] + b[xx];
ans = max(ans, dp[seq[xx]]);
}
}
}
cout << ans << endl;
}
}