题解:2018级算法第六次上机 C6-危机合约

题目描述

样例:

 

实现解释:

没想到你也是个刀客塔之二维DP

知识点:

动态规划,多条流水线调度?可以看做一种流水线调度

坑点:

输入内容的调整(*的特殊判定),开头结尾的调整策略

 

从题意可知,要做的就是从起始点移动到蓝点,并且在过程中会有一个值的记录,这就可以和一些基础题目联系起来:捡金币问题,流水线问题等等。

不过注意在使用板子时需要注意值的调度策略:对无法过去的地点,可将敌人攻击值设为99999,即无限,从而在进行动态规划时也可直接参与计算。借助这一攻击无限化的想法,对第一列和最后一列也需要进行处理:无法从开始点直接进入的第一列的值和无法在最后一列到达结束点,同样是到达无意义(无法上下移动),因此设为无穷。

调整之后便可直接借助dp进行,假设dp数组为dp[i][j]:到达第ij列时的最小受损值。则很容易可得到状态转移方程:dp[i][j] = min(dp[i][j-1],dp[i-1][j-1],dp[i+1][j-1]) + a[i][j];

基于方程递归进行即可,注意dp的初始化(第一列),这里由于是参考多条流水线进行的编写,因此应该会很熟悉。

 

完整代码:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define NO 99999
int a[110][110];
int main()
{
    ios::sync_with_stdio(false);
    int n,m;
    cin >> n >> m;
    int a[n][m];
    int dp[n][m];
    int h,from,to;
    char temp;
    cin >> h >> from >> to;
    for(int i = 0;i<n;i++)
    {
        for(int j = 1;j<=m;j++)
        {
            cin >> temp;//便于比较是否可通行 
            if(temp == '*') a[i][j] = NO;//不可通行则设为一定死的值
            else a[i][j] = temp-'0';//否则存储数字 
        }
    }
    from -= 1;
    to -= 1;
    //这里是为了和脚标配合进行的处理 
    for(int i = 0;i<n;i++)
    {
        //第一列中开局不能到达的,最后一列中不能到结束点的
        //相当于不可达,设为大值 
        if(abs(from-i) > 1) a[i][1] = NO;
        if(abs(to-i) > 1) a[i][m] = NO;
    }
    for(int i = 0;i<n;i++)
    {
        //象征性的初始化,第一列 
        dp[i][1] = a[i][1];
    }
    int tempf;//存储临时的掉血数 
    for(int i = 2;i<=m;i++)
    {
        for(int j = 0;j<n;j++)
        {
            //向右走 
            tempf = dp[j][i-1]+a[j][i];
            //判断右上和右下 
            for(int k = -1;k<=1;k+=2)
            {
                //越界则跳过 
                if(j+k<0||j+k>n-1) continue;
                if(tempf > dp[j+k][i-1]+a[j][i])
                {
                    tempf = dp[j+k][i-1]+a[j][i];
                }
            }
            dp[j][i] = tempf;
        }
    }
    //获取最小值设为最大值 
    tempf = NO;
    for(int k = -1;k<=1;k++)
    {
        if(to+k<0||to+k>n-1) continue;//越界跳过 
        if(dp[to+k][m] > NO) continue;//有不可达的点,跳过 
        if(dp[to+k][m] < tempf) tempf = dp[to+k][m];//最小值 
    }
    //判断最小掉血数和hp的关系 
    if(tempf-h > 0) cout << "doctor win\n";
    else cout << h-tempf << '\n';
    return 0;
}
View Code

 

posted @ 2019-11-28 11:31  稼軒  阅读(252)  评论(0编辑  收藏  举报