FatMouse and Cheese HDU - 1078 (记忆化搜索+拓扑排序)

传送门

题意:n*n格子(1<=n<=100),每个格子有一个数a[i][j](范围在0~100)。每次只能横或竖直跳,且最多跳k格,跳的下一位数要比当前位大。从(1,1)开始跳,问跳的数的和的最大值。

题解:记忆化搜索见代码

代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>

using namespace std;
const int N = 1e2 + 10;

int n, k;
int a[N][N], dp[N][N];
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
int dfs(int x, int y) {
    if (dp[x][y]) return dp[x][y];
    int mx = a[x][y];  //注意这个,如果设置为0 就会出错
    for (int i = 1; i <= k; i++) {
        for (int j = 0; j < 4; j++) {
            int nx = x + i * dx[j], ny = y + i * dy[j];
            if (nx < 1 || nx > n || ny < 1 || ny > n) continue;
            if (a[nx][ny] > a[x][y]) mx = max(mx, dfs(nx, ny) + a[x][y]);
        }
    }
    return dp[x][y] = mx;
}
signed main() {
    while (cin >> n >> k) {
        if (n == -1 && k == -1) break;
        int i, j;
        for (i = 1; i <= n; i++)
            for (j = 1; j <= n; j++) scanf("%d", &a[i][j]);
        dfs(1, 1);
        cout << dp[1][1] << endl;
        memset(dp, 0, sizeof(dp));
    }
    return 0;
}

补充:

  • 记忆化搜索-dfs优化(量化dfs,即dfs(x,y)=dp[x][y])
  • 不浪费时间,实在想不出来可以立即溜(换一种思路)。甚至可以直接放弃原来的思路。

不知道为什莫拓扑排序的代码ac不了:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#define pb push_back
#define dbg(x) cout << #x << "===" << x << endl
#define ed(x, y) (x) * (n) + (y)
using namespace std;
const int N = 1e2 + 10;
const int INF = 2e9;

int n, k;
int a[10010], dp[10010];
int du[10010];
vector<int> g[10010];
int topo() {
    queue<int> q;
    int i, j, t, x, res = 0;
    q.push(0), dp[0] = a[0];
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            if (du[ed(i, j)] == 0) {
                if (i + j == 0) continue;
                for (auto t : g[ed(i, j)]) du[t]--;  //这里神来之笔
            }
        }
    }
    // dbg(q.size());
    while (!q.empty()) {
        x = q.front();
        q.pop();
        res = max(res, dp[x]);
        for (auto i : g[x]) {
            dp[i] = max(dp[i], dp[x] + a[i]);
            du[i]--;
            if (du[i] == 0) q.push(i);
        }
    }
    // for (i = 0; i < n; i++) {
    // for (j = 0; j < n; j++) {
    // cout << dp[i][j] << " ";
    // }
    // cout << endl;
    // }
    return res;
}
void init() {
    memset(a, 0, sizeof(a));
    memset(dp, 0, sizeof(dp));
    memset(du, 0, sizeof(du));
    for (int i = 0; i < n * n; i++) g[i].clear();
}
int main() {
    while (cin >> n >> k) {
        if (n == -1 && k == -1) break;
        init();
        int i, j, t;
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++) scanf("%d", &a[ed(i, j)]);
        // for (i = 0; i < n; i++)
        // for (j = 0; j < n; j++) cout << a[i][j] << " ";
        // cout << endl;
        int l, r;
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
                if (a[ed(i, j)] <= a[0] && i + j > 0) continue;  //不配
                // cout << i << " " << j << "<<<" << endl;
                l = max(j - k, 0), r = min(j + k, n - 1);
                for (t = l; t <= r; t++) {
                    if (t == j || a[ed(i, t)] <= a[ed(i, j)]) continue;
                    g[ed(i, j)].pb(ed(i, t));
                    du[ed(i, t)]++;
                }
                l = max(i - k, 0), r = min(i + k, n - 1);
                for (t = l; t <= r; t++) {
                    if (t == i || a[ed(t, j)] <= a[ed(i, j)]) continue;
                    g[ed(i, j)].pb(ed(t, j));
                    du[ed(t, j)]++;
                }
            }
        }  //最多2*100^3条边
        // for (i = 0; i < n * n - 1; i++) {
        // dbg(i);
        // for (auto j : g[i]) {
        // cout << j << " ";
        // }
        // cout << endl;
        // }
        cout << topo() << endl;
    }
    return 0;
}
/*
input:::
3 1
1 2 5
10 11 6
12 12 7
-1 -1
output:::
37
*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值