HDU - 4784 Dinner Coming Soon (dp)

题目链接

https://vjudge.net/problem/HDU-4784

题目大意

1 1 1号点走到 n n n号点,有 m m m条有向路径,每条路径需要花费时间和路费,初始有r元,在每个点可以选择买入 o r or or 卖出 商品 o r or or不做 商品最多携带 b b b个, 共有 [ 0 , k − 1 ] [0,k-1] [0,k1]个空间,可以花费 1 1 1的时间穿越到 ( i + 1 ) (i+1)%k (i+1)号空间,不同空间的交易价格不同,路径相同。此人不能穿越到1号点和n号点的非 0 0 0号空间 ,问在T时间内到达n号点时最大的所持金钱是多少

题解思路

这题主要是想学一下写法,参考了别人的思路,代码写的很漂亮。
想法其实很简单,虽然循环多但是数据量很小。
d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l]在第i分钟在j城 k维 携带l袋盐所对应的最大价值
转移的方向先考虑在当前点的三种方案(买 卖 不做)
再考虑下一个点,可以选择穿越 或者 走起点为该点转移到下一个点。

贪心考虑 最优状态一定在最后一个点的时候身上一袋盐都不剩,枚举一下时间取max就是答案

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
//#define int ll
#define debug cout<<"fuck"<<endl;
#define pb  push_back
#define endl '\n'
#define fi first
#define se second
#define db double
#define pii pair<int,int>
#define mp make_pair
const int mod=(int)1e9+7;
const int maxn=(int)105;
int add(int a, int b) {if((a += b) >= mod) a -= mod; return a < 0 ? a + mod : a;}
int mul(int a, int b) {return 1ll * a * b % mod;}

int t,n,m,b,d,r;
int dp[205][105][6][6];//在第i分钟在j城 k维 携带l袋盐所对应的最大价值
int p[6][maxn];


struct edge
{
    int to,tim,val;
};
vector<edge>v[maxn];

void trans(int i,int j,int k,int l,int val)
{
    for(auto edg:v[j])
    {
        if(val>=edg.val&&i+edg.tim<=t)
        {
            dp[i+edg.tim][edg.to][k][l]=max(dp[i+edg.tim][edg.to][k][l],val-edg.val);
        }
    }
    if(i+1<=t&&j!=1)
    dp[i+1][j][(k+1)%d][l]=max(dp[i+1][j][(k+1)%d][l],val);
}

void init()
{
    for(int i=0;i<maxn;i++)
    {
        v[i].clear();
    }
    memset(dp,-1,sizeof(dp));
}

int main()
{
    IOS
    int T;
    cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        init();
        cin>>n>>m>>b>>d>>r>>t;
        //n个屋子 m条路 盐的携带上限为b 维度[0,d-1] 最初有r元 时间上限为t
        for(int i=0;i<d;i++)
        {
            for(int j=1;j<=n;j++)
            {
                cin>>p[i][j];
            }
        }
        int x,y,minu,yuan;
        edge tem;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>y>>minu>>yuan;
            tem.to=y;
            tem.tim=minu;
            tem.val=yuan;
            v[x].pb(tem);
        }
        dp[0][1][0][0]=r;
        for(int i=0;i<=t;i++)//时间
        {
            for(int j=1;j<n;j++)//城市
            {
                for(int k=0;k<d;k++)//维
                {
                    for(int l=0;l<=b;l++)//携带数
                    {
                        int valu=dp[i][j][k][l];
                        if(valu==-1)continue;
                        //买 卖 不做
                        if(j!=1&&l+1<=b&&valu>=p[k][j])
                            trans(i,j,k,l+1,valu-p[k][j]);

                        if(j!=1&&l)
                            trans(i,j,k,l-1,valu+p[k][j]);

                        trans(i,j,k,l,valu);
                    }
                }
            }
        }

        int ans=-1;
        for(int i=0;i<=t;i++)
        {
            ans=max(ans,dp[i][n][0][0]);
        }
        cout<<"Case #"<<kase<<": ";
        if(ans!=-1)cout<<ans<<endl;
        else cout<<"Forever Alone"<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值