ZOJ 3431 Escape! 解题报告

39 篇文章 0 订阅

题目

题意:

主角要从一座塔中逃脱,每一层除了出口外,还有不超过5个的宝藏,而且每层还有倒塌时间。求在成功离开的前提下,能拿到的最大财宝价值。

题解:

对每一层做预处理,计算从入口选择某几个宝藏再到出口所花的最少时间。然后对每层做dp[i],i表示到这层的时间为i,然后枚举所有选宝藏的方案来转移。


//Time:190ms
//Memory:280KB
//Length:2647B
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 105
#define MAXT 1300
#define INF 1000000007
int n;
int x[MAXN],y[MAXN],num[MAXN],ti[MAXN];
int px[MAXN][10],py[MAXN][10],v[10],dp_t[MAXN][32][5],val[MAXN][32];
int dp[2][MAXT];
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int cas;
    scanf("%d",&cas);
    while (cas--)
    {
        scanf("%d",&n);
        for (int i=0;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
        memset(dp_t,0x3f,sizeof(dp_t));
        memset(val,0,sizeof(val));
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            for (int j=0;j<num[i];j++)
                scanf("%d%d%d",&px[i][j],&py[i][j],&v[j]);
            for (int j=0;j<(1<<num[i]);j++)
                for (int k=0;k<num[i];k++)
                if ((j&(1<<k))!=0) val[i][j]+=v[k];
            for (int j=0;j<num[i];j++)
                dp_t[i][(1<<j)][j]=abs(x[i-1]-px[i][j])+abs(y[i-1]-py[i][j]);
            for (int j=0;j<(1<<num[i]);j++)
                for (int pre=0;pre<num[i];pre++)
                    if ((j&(1<<pre))!=0)
                        for (int now=0;now<num[i];now++)
                            if ((j&(1<<now))==0)
                            {
                                int sta=j|(1<<now);
                                dp_t[i][sta][now]=min(dp_t[i][j][pre]+abs(px[i][pre]-px[i][now])+abs(py[i][pre]-py[i][now]),dp_t[i][sta][now]);
                            }
        }
        for (int i=1;i<=n;i++) scanf("%d",&ti[i]);
        memset(dp,-0x3f,sizeof(dp));
        dp[0][0]=0;
        int s=1;
        for (int i=1;i<=n;i++)
        {
            memset(dp[s],-0x3f,sizeof(dp[s]));
            for (int t=0;t<=ti[i];t++)
                if (dp[!s][t]>-INF)
                {
                    int tmp=t+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
                    if (tmp<=ti[i])
                        dp[s][tmp]=max(dp[s][tmp],dp[!s][t]);
                    for (int k=0;k<num[i];k++)
                    {
                        for (int j=0;j<(1<<num[i]);j++)
                        {
                            tmp=t+dp_t[i][j][k]+abs(x[i]-px[i][k])+abs(y[i]-py[i][k]);
                            if (tmp<=ti[i])
                                dp[s][tmp]=max(dp[s][tmp],dp[!s][t]+val[i][j]);
                        }
                    }
                }
            s=!s;
        }
        int ans=-INF;
        for (int t=0;t<=ti[n];t++)
            ans=max(ans,dp[!s][t]);
        if (ans<=-INF) printf("I'm doomed, though I fought bravely\n");
        else printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值