HDU5115(区间dp)详解

来源:互联网 发布:大学c语言入门 编辑:程序博客网 时间:2024/06/04 18:55

题目大意:你是一个战士现在面对,一群狼,每只狼都有一定的主动攻击力和附带攻击力。你杀死一只狼。你会受到这只狼的(主动攻击力+旁边两只狼的附带攻击力)这么多伤害~现在问你如何选择杀狼的顺序使的杀完所有狼时,自己受到的伤害最小。(提醒,狼杀死后就消失,身边原本相隔的两只狼会变成相邻,而且不需要考虑狼围城环这种情况)

输入要求:总共T组数据,每组N只狼,按顺序输入全部狼的主动攻击力和然后再按顺序输入全部狼的附带攻击力

输出要求:Case #x: y x第几组数据,y最少受到的伤害

思路引导:首先所有狼的主动攻击一定是必须全部加上的然后,然后就是调整附带伤害的顺序来求出最小值。
样例解释:
2

输入
3
3 5 7
8 2 0
输出
Case #1: 17
杀序号1的狼 3+2=5
杀序号2的狼 5+0=5
杀序号3的狼 7+0=7
总的伤害5+5+7=17;

10
1 3 5 7 9 2 4 6 8 10
9 4 1 2 1 2 1 4 5 1
Case #2: 74
主动伤害总和1+3+5+7+9+2+4+6+8+10=55;
附带伤害总和
因为数字比较多我这次列出全部过程
【1】3 5 7 9 2 4 6 8 10
【9】 4 1 2 1 2 1 4 5 1
附带伤害 4
【1 3】 5 7 9 2 4 6 8 10
【9 4】 1 2 1 2 1 4 5 1
附带伤害 1
【1 3 】5 【7】 9 2 4 6 8 10
【9 4】 1 【2】 1 2 1 4 5 1
附带伤害 1+1=2
【1 3】 5【 7】 9 【2】 4 6 8 10
【9 4】 1 【2】 1 【2】 1 4 5 1
附带伤害 1+1=2;
此时实际序列5 9 4 6 8 10
1 1 1 4 5 1
【1 3】 5【 7】 9 【2】 4 6【 8】 10
【9 4】 1 【2】 1 【2】 1 4 【5】 1
附带伤害 4+1=5
【1 3】 5【 7】 9 【2】 4【 6 8】 10
【9 4】 1 【2】 1 【2】 1 【4 5】1
附带伤害 1+1=2
剩下4只狼
5 9 4 10
1 1 1 1
从左边杀起,因这样每次只有右边有附带伤害
1+1+1=3
附带伤害总和4+1+2+2+5+2+3=19
总和伤害55+19=74
通过样例我们可以总结出来如果有附带伤害高的狼先杀他,然后尽量杀两端的狼,这样只有一边有附带伤害

程序分析
区间dp的模式都是差不多的,最外面一层枚举长度,第二层枚举起点所以i

    for(len=1;len<=n;len++)        {            for(i=1;i<=n-len+1;i++)            {                j=i+len-1;                for(k=i;k<=j;k++)                {                    dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+attack[k]+extre[i-1]+extre[j+1]);                }            }        }
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>using namespace std;#define INF 0x3f3f3f3f//记住一定是四个3f五个就是六十四位了int attack[210];int extre[210];int dp[210][210];//第i到第j个的最小受到伤害int main(){    int T;    int cas;    scanf("%d",&T);    for(cas=1;cas<=T;cas++)    {        int n;        int len,i,j,k;        scanf("%d",&n);        for(i=1;i<=n;i++)        {            scanf("%d",&attack[i]);        }        for(i=1;i<=n;i++)        {            scanf("%d",&extre[i]);        }        extre[0]=0;//初始化边界,当杀两端狼时的情况        extre[n+1]=0;        for(i=1;i<=n;i++)        {            for(j=i;j<=n;j++)            {                dp[i][j]=INF;            }        }//刚开始我写成memset(dp,INF,sizeof(dp));这样是错的因为下面有dp[i][k-1]+dp[k+1][j]在每次循环时第一遍因为j==k,所以k+1>j;        //如果按memset初始化,dp[k+1][j]和[dp[i][j]都是超级大的数,min就会出错。        for(i=0;i<=n;i++)//初始化边界,当杀两端狼时的情况        {            dp[0][i]=0;            dp[i][n+1]=0;        }           for(len=1;len<=n;len++)        {            for(i=1;i<=n-len+1;i++)            {                j=i+len-1;                for(k=i;k<=j;k++)                {                    dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+attack[k]+extre[i-1]+extre[j+1]);                }            }        }        printf("Case #%d: %d\n",cas,dp[1][n]);    }    return 0;}
1 0
原创粉丝点击