蒜头君的坐骑

蒜头君的坐骑

题目描述

蒜头君有一只坐骑,人马。

一天,蒜头君骑着他的坐骑走上了一片 n×m 的大荒野,一开始时,蒜头君在 (1,1) 点,他要前往(n,m) 点,蒜头君的人马每次可以向右或向下移动一格。然而这片荒野并不平静,除了起点和终点外每个点都有一只怪物会袭击蒜头君。

然而蒜头君的人马强大无比,它会先对怪物造成等同于它攻击力的伤害,然后蒜头君才会受到怪物的攻击,伤害等同于怪物的攻击力。然后人马再攻击怪物,怪物再攻击蒜头君,直至怪物死去,假设每个怪物具有相同的体力。

此外,蒜头君的人马还有一个强大无比的技能,使用该技能会使蒜头君接下来 k 次移动,每一次移动后增加等同于移动到的格子的怪物的攻击力,k 次移动后,人马攻击力恢复至初始攻击力。人马必须在当前一个技能释放完后才可以释放下一个技能,且一共可释放技能的次数有限,那么试问蒜头君从起点到终点最少受到多少点伤害。

注意:蒜头君的体力是无限的。

输入输出格式

输入格式:

第一行六个正整数 n,m,t,k,h,atk,表示地图长度、宽度、人马技能可使用次数、人马技能持续移动次数、每只怪物的体力和人马的初始攻击力。保证 n+m−1≥t×k。

接下来 n 行,每行 m 个整数,表示每个点的怪物的攻击力。保证 (1,1) 点、(n,m) 点为 0,其他点为正整数。

输出格式:

输出一个整数,表示蒜头君受到的最小伤害。

说明

对于 30% 的测试数据,满足 1≤n,m≤10, 1≤t≤3, 1≤k≤3;

对于 60% 的测试数据,满足 1≤n,m≤100, 1≤t≤10, 1≤k≤5;

对于 100% 的测试数据,满足1≤n,m≤500, 1≤t≤10, 1≤k≤5, 1≤atk≤h≤100, 1≤ 怪物攻击力 ≤100。


第一次做类似的题目,算做积累了。

思想不难,就是整体DP,局部搜索。(据说还有一种有后效性的DP是整体DP,局部高斯消元)

\(dp[i][j][k]\)\(i\)\(j\)列第\(k\)次使用技能的最小伤害。

当不释放技能时,直接转移:(cnt为原始攻击需要打的次数)

dp[i+1][j][l]=min(dp[i+1][j][l],dp[i][j][l]+cnt*atk[i+1][j]);
dp[i][j+1][l]=min(dp[i][j+1][l],dp[i][j][l]+cnt*atk[i][j+1]);

搜索释放技能能到达的答案并更新dp。

为了确保这样是对的,有这样一句话“使用该技能会使蒜头君接下来 k 次移动,每一次移动后增加等同于移动到的格子的怪物的攻击力”,也就是说,放技能是连续的。而k值的范围又小。

整体复杂度\(O(nmtk!)\),基本能过


code:

#include <cstdio>
#include <cstring>
int min(int x,int y){return x<y?x:y;}
const int N=502;
int n,m,t,k,h,atk0;
//长、宽、使用次数、持续移动次数、怪物体力和初始攻击力
int dp[N][N][12],atk[N][N];
void dfs(int i,int j,int tt,int atkk,int cntt,int mi)
{
    if(cntt>k)
        return;
    atkk+=atk[i][j];
    mi+=atk[i][j]*(h%atkk?h/atkk:h/atkk-1);
    dp[i][j][tt]=min(dp[i][j][tt],mi);
    if(i<n)
        dfs(i+1,j,tt,atkk,cntt+1,mi);
    if(j<m)
        dfs(i,j+1,tt,atkk,cntt+1,mi);
}
int main()
{
    scanf("%d%d%d%d%d%d",&n,&m,&t,&k,&h,&atk0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&atk[i][j]);
    int cnt=h%atk0?h/atk0:h/atk0-1;
    memset(dp,0x3f,sizeof(dp));
    dp[1][1][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int l=0;l<=t;l++)
            {
                dp[i+1][j][l]=min(dp[i+1][j][l],dp[i][j][l]+cnt*atk[i+1][j]);
                dp[i][j+1][l]=min(dp[i][j+1][l],dp[i][j][l]+cnt*atk[i][j+1]);
                if(l<t)
                {
                    if(i<n)
                        dfs(i+1,j,l+1,atk0,1,dp[i][j][l]);
                    if(j<m)
                        dfs(i,j+1,l+1,atk0,1,dp[i][j][l]);
                }
            }
    printf("%d\n",dp[n][m][t]);
    return 0;
}


2018.6.23

posted @ 2018-06-23 17:51  露迭月  阅读(236)  评论(0编辑  收藏  举报