hdu 4517 floyd+记忆化搜索

题意:

有n(100)个景点,m(1000)条路,时间限制为t(300),起点s,终点e。

访问每个景点需要时间cost_i,每个景点的访问价值为value_i。

点与点之间行走需要花费的时间为g[ i ] [ j ] 。注意点间可能有多条边。

走到一个点时可以选择访问或者不访问,并且当前点的访问价值应该严格大于前一个访问的点。

现在求,从起点出发,到达终点,在时间限制内,能得到的最大价值为多少。

如果不能从s到达e,则输出0。


解析:

首先应该走到一个点可以选择访问或者不访问,所以可以用floyd求出点与点之间最近的距离为多少。

然后dp[ i ] [ j ] [ k ] 表示的是,当前走到 i 点,前一个点的价值为 j ,并且还有剩余时间 k 的最大价值。

详见代码。


代码:

#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cassert>
#include <iostream>
#include <algorithm>
#define pb push_back
#define mp make_pair
#define LL long long
#define lson lo,mi,rt<<1
#define rson mi+1,hi,rt<<1|1
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i,a,b) for(int i=(a); i<=(b); i++)
#define dec(i,a,b) for(int i=(a); i>=(b); i--)

using namespace std;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double ee = exp(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 100 + 10;
const int maxt = 300 + 10;
const double pi = acos(-1.0);
const LL iinf = 0x3f3f3f3f3f3f3f3f;

int readT()
{
    char c;
    int ret = 0,flg = 0;
    while(c = getchar(), (c < '0' || c > '9') && c != '-');
    if(c == '-') flg = 1;
    else ret = c ^ 48;
    while( c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c ^ 48);
    return flg ? - ret : ret;
}

int n, m, t, s, e;
int g[maxn][maxn];
int dp[maxn][maxn][maxt];
int cost[maxn];
int value[maxn];

void floyd()
{
    rep(i, 0, n - 1)
    {
        g[i][i] = 0;
    }
    rep(k, 0, n - 1)
    {
        rep(i, 0, n - 1)
        {
            rep(j, 0, n - 1)
            {
                g[i][j] = Min(g[i][j], g[i][k] + g[k][j]);
            }
        }
    }
}

int dfs(int u, int preVal, int timeLeft)
{
    if (g[u][e] > timeLeft)
        return -inf;

    int& res = dp[u][preVal][timeLeft];
    if (res != -1)
        return res;

    res = 0;
    rep(i, 0, n - 1)
    {
        if (preVal < value[i])
        {
            res = Max(res, dfs(i, value[i], timeLeft - g[u][i] - cost[i]) + value[i]);
        }
    }
    return res;
}

int main()
{
#ifdef LOCAL
    FIN;
#endif // LOCAL
    int ncase = readT();
    int ca = 1;
    while (ncase--)
    {
        scanf("%d%d%d%d%d", &n, &m, &t, &s, &e);
        mem(dp, -1);
        mem(g, inf);
        rep(i, 0, n - 1)
        {
            cost[i] = readT();
        }
        rep(i, 0, n - 1)
        {
            value[i] = readT();
        }
        rep(i, 0, m - 1)
        {
            int u = readT();
            int v = readT();
            int w = readT();
            g[u][v] = g[v][u] = Min(g[u][v], w);
        }
        floyd();
        int ans = dfs(s, 0, t);
        printf("Case #%d:\n", ca++);
        printf("%d\n", ans == -inf ? 0 : ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值