男神的礼物(区间dp变式)

描述:
Lweb学长是集训队里公认的男神。有一天他要给美美的学姐姐准备礼物。

Lweb学长可是会魔法的哟。为了准备一份礼物,男神要加工n份材料。每一次只能加工相邻的材料。

当男神加工两个魔法值为a,b的材料,男神都要消耗a*b的体力,同时在这个地方合成出魔法值(a+b)%100的材料。

男神为了能节省体力来完成他的礼物。想找聪明的你帮他算一算他所要花费的最小体力。

Input
第一行一个整数T,表示男神所要准备的礼物数。
之后的T组数据各有两行数据,第一行有一个整数n,表示这份礼物的材料数(1<=n<=100)。
接下来一行有n个整数a(0<=a<100),表示这件礼物第i份材料的魔法值。

Output
每组数据一行输出,表示男神制作这份礼物所要的最小体力。

Sample Input
2
2
18 19
3
40 60 20
Sample Output
342
2400
Hint
对于样例 2:

先加工材料40和60,得到0的材料,消耗40∗∗60体力,共消耗2400体力;

再加工材料0和20,得到20的材料,消耗0∗∗20体力,共消耗2400体力.

这道dp题与之前的矩阵消解和合并石子不太相同的地方是,两个数字合并以后会产生一个新数,我们可以不管这个数是以何种方式产生的,而把这个归结到一类题型(对于这道题,新数的产生方式是(a+b)%100)
,所以在进行dp的一个状态,不仅需要记录这个状态的最小花费,还要记录这个在这个花费下所产生的数。这样我们就需要一个结构体来保存这两个值分布设为v和g。(对问题的分析要寻求已知知识不假,但是要找到不同之处。怎么去处理这个不同,是要去寻找问题的本质,并且总结、归纳一个此类型的题目,并延伸)
花费状态dp[i][j].v:区间i到j合并以后所花费的最小值。
数dp[i][j].g:在最小花费的情况下所合成的新数。
花费状态转移方程:dp[i][j].v=min{dp[i][k].v+dp[k+1][j].v+dp[i][k].g*dp[k+1][j].g | k大于等于i小于等于j}
数状态转移方程:设k为使得在这个分割似的上述cost状态dp[i][j].v最小,则dp[i][j].g=(dp[i][k].g+dp[k+1][j].g)%100。
代码:

import java.util.Scanner;

public class Main
{   
    public static void main(String[] args) 
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        while((t--)>0)
        {
            int n=sc.nextInt();
            node dp[][]=new node[n+1][n+1];//node定义见下
            for(int i=1;i<=n;i++)
                dp[i][i]=new node(0,sc.nextInt());//单个数不需要合并,所以花费为0,并且这个状态下的数是其本身
            for(int len=2;len<=n;len++)//因为长度为1已经处理过了,只要从长度为2的区间开始
            {
                for(int i=1;i+len<=n+1;i++)
                {
                    int j=i+len-1;

                    dp[i][j]=new node(Integer.MAX_VALUE,0);//因为是类,需先指向对象
                    for(int k=i;k<j;k++)
                    {
                        if(dp[i][j].v>dp[i][k].v+dp[k+1][j].v+dp[i][k].g*dp[k+1][j].g)//因为需要数的合成,所有这里的写法与之前不太一样,只要大于,同时两个状态赋值,这样代码编写简便一些
                        {
                            dp[i][j].v=dp[i][k].v+dp[k+1][j].v+dp[i][k].g*dp[k+1][j].g;
                            dp[i][j].g=(dp[i][k].g+dp[k+1][j].g)%100;
                        }
                    }
                }
            }
            System.out.println(dp[1][n].v);//输出即可,假如题目换一个问法,在最小花费的情况下输出这个时候的最后留下的数,那只要输出dp[1][n].g即可
        }
    }   
}
class node
{
    int v;
    int g;
    node(int v,int g)
    {
        this.v=v;
        this.g=g;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值