HDU1078 记忆化搜索

原题链接: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;
    }
}

你可能感兴趣的:(HDU)