ZOJ 3431 Escape!

在面临城堡自动摧毁的情况下,玩家需要在限定时间内从最高楼层逃到一楼,并尽可能收集最多宝藏。通过动态规划方法,玩家可以决定每层楼是否收集宝藏、收集哪些宝藏以及收集的顺序,以最大化总价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Escape!

Time Limit: 2 Seconds       Memory Limit: 65536 KB

The usual stuff, after you beat the boss at the topmost floor of his castle, the evil boss triggers the auto destruct function of his castle, and you must escape! However, not so fast! You have fought really bravely and it seems you do deserve some rewards. There are N floors in the castle, and there are treasures lying about in the castle, you want to escape and get as much treasure as you can. Each piece of treasure has a value, and you would want to maximize the sum. With the auto destruction of the castle imminent, the exit stair of floor i will crumple after Ti minutes (it's still open at the Ti-th minute), you do not want to left buried in the castle, so you have to leave the i-th floor in Ti-th minute.

Input

The first line of the input is T (T≤100), the number of testcases. Then T blocks follow, each has the form: an integer N (N≤100), the number of floors. IntegersXY, your initial position on the N-th floor. Then N lnteger pairs, each being the Xi and Yi, coordinate of the stairs of the i-th floor, then N lines follow each with the form: an integer Mi (0≤Mi≤5), the number of treasure of the i-th floor. Then Mi triples follow, each being a piece of treasure's X and Y coordinate and it's value. Then N integers, the i-th is Ti (Ti ≤ 1200). All the input above are given in the order of N to 1. All coordinates are in range [-1200,1200].

Output

The maximum value you can get or "I'm doomed, though I fought bravely" if you cannot escape. Assume you can only go X and Y direction and your speed is 1 unit per minute.

Sample Input
1
1
0 0
10 10
1 4 5 10
1000
Sample Output

10


ZOJ月赛的一个题,参考了代码 ZOJ Monthly, November 2010解题报告

题意:一个人要从房间里面逃跑,共N层,现在他在第N层,要跑到一楼出口。告诉一个在第N层的起始坐标,每一层的出口坐标。每一层都有m个宝藏,这个人在保证能逃跑出去的前提下,希望尽量多的拿到宝藏,三个数一组,分别表示宝藏的坐标和价值,每层m组。最后N个数,每一层可以待的最长时限,超过这个时间,这一层就会塌陷。注意距离为曼哈顿距离。


分析:dp题,枚举每一层对于m个宝藏拿多少,拿的顺序是什么,选择个数共有C(m,1)+C(m,2)`````+C(m,m)=2^m-1种情况,对于每种情况再枚举取的顺序。

#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int N = 222;

int n;
int fk[]={1,2,4,8,16,32,64,128};
int dp[N][2400];
int m[N];
int x[N],y[N];//每层出口坐标
int xx[N][5],yy[N][5],val[N][5];//每层宝藏坐标和价值
int t[N];

void update(int pos,int val,int c)
{
    for(int i=c;i<=t[pos];i++)
    dp[pos][i]=max(dp[pos][i],dp[pos+1][i-c]+val);
}

void fun(int pos)
{
    int a[10];
    update(pos,0,abs(x[pos+1]-x[pos])+abs(y[pos+1]-y[pos]));//不拿宝藏时
    int cnt;
    int v;

    for(int i=1;i<fk[m[pos]];i++)
    {
        cnt=0;v=0;
        for(int j=0;j<m[pos];j++)
            if(fk[j]&i)
            {
                v+=val[pos][j];
                a[cnt++]=j;
            }
        int len=99999999;
        int tmp;
        do{
            tmp=abs(xx[pos][a[0]]-x[pos+1])+abs(yy[pos][a[0]]-y[pos+1]);
            for(int j=1;j<cnt;j++)
            tmp+=abs(xx[pos][a[j]]-xx[pos][a[j-1]])+abs(yy[pos][a[j]]-yy[pos][a[j-1]]);
            tmp+=abs(xx[pos][a[cnt-1]]-x[pos])+abs(yy[pos][a[cnt-1]]-y[pos]);

            len=min(len,tmp);
        }while(next_permutation(a,a+cnt));//变换到比当前字典序大一的排列,枚举取的顺序

        update(pos,v,len);
    }
}

int main()
{
    int T;

    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=n;i>=0;i--)
            scanf("%d%d",&x[i],&y[i]);

        for(int i=n-1;i>=0;i--)
        {
            scanf("%d",&m[i]);
            for(int j=0;j<m[i];j++)
            scanf("%d%d%d",&xx[i][j],&yy[i][j],&val[i][j]);
        }

        int time=0;
        for(int i=n-1;i>=0;i--)
        {
            scanf("%d",&t[i]);
            time=max(time,t[i]);
        }

        for(int i=0;i<=n;i++)
        for(int j=0;j<=time;j++)
            dp[i][j]=-99999999;

            dp[n][0]=0;

        for(int i=n-1;i>=0;i--)
            fun(i);

        int ans=dp[0][0];
        for(int i=1;i<=time;i++)
        ans=max(ans,dp[0][i]);

        if(ans<0)
        puts("I'm doomed, though I fought bravely");
        else
        printf("%d\n",ans);
    }
<span style="font-family: Arial, Helvetica, sans-serif;">return 0;</span>
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值