筷子

前言
“我是白领:今天领了薪水,交了房租水电,买了青菜大米,工资就白领了 ”。欢迎来到嘟嘟课堂。今天,嘟嘟老师讲一道DP的题——筷子。
题目描述
一个怪人,吃东西时使用三根筷子,二短一长,设它们的长为A≤B≤C。并定义它的”坏度”为(A - B)^2。这一天,他要请K个客人来家里吃饭,另外他自己家里还有8个人,因而要准备K+8套这种特别的筷子。但发现家里的筷子全是不一样长的。
请你将这些筷子分成K+8套,要求总的”坏度”值最小。
输入
第一行一个整数T,表示测试数据的组数,每组测试数据输入共2行:
第1行两个整数K和N,分别表示要请K个客人来家里吃饭,家里共有N根长度不一的筷子。
第2行包含N个非负整数L[i],描述第i根筷子的长度,输入时L[i]已经从小到大排列。
输出
对于每组测试数据输出一行,表示最小的“坏度”值之和。
样例输入
1
1 40
1 8 10 16 19 22 27 33 36 40 47 52 56 61 63 71 72 75 81 81 84 88 96 98 103 110 113 118 124 128 129 134 134 139 148 157 157 160 162 164
样例输出
23
样例说明
样例中要组合9套筷子,一种可能的组合是:8,10,16;19,22,27; 61,63,75;71,72,88;81,81,84;96,98,103;128,129,148;134,134,139;157,157,160。
数据范围限制
数据没有梯度。
100%的数据:T=2,0≤ K ≤1000, 3K+24≤ N ≤5000, 1≤ L[i] ≤32000。
思路
这道题很多人想用贪心来水分。可是Sorry,贪心是爆蛋的!
这其实是一道很坑的DP。
我们不能让选出来的A、B两根筷子筷子找不到它们的伙伴C筷子。
这题的动态转移方程并不难推。但很多人都没AC。不用怕,嘟嘟老师一点就通。
筷子的长度a[i]是单调递增的
一套筷子的A、B肯定相邻的a[i-1],a[i]
设f[i,j]表示前1~i根筷子组合j套时候的最优值
怎么选C?(第三根,就是那根最长的)
把a数组从大到小排列(直接从大到小读入就行了),i始终保证i≥3*j,这样就肯定有筷子能做C,能保证C是最大
f[i,j]表示的是前i根筷子前j个人最少的质量和是多少。 那么就要考虑第i跟筷子选不选给第j个人,如果选的话就是f[ i -2,j - 1] + (a[i] - a[i - 1])的平方(因为选了第i根筷子的话就要选第i - 1根筷子),如果不选的话,那么就是f[i -1,j]。
还不懂的童鞋们再看几遍思路。
再看几遍……再看几遍……
代码

uses math;
var
        a:array[0..5000] of longint;
        f:array[0..5000,0..5000] of longint;
        i,j,k,n,l,t,g:longint;
begin
        readln(t);
        for l:=1 to t do
        begin
                readln(k,n);
                k:=k+8;
                for i:=n downto 1 do
                        read(a[i]);
                for i:=1 to n do
                begin
                        for j:=0 to k do
                                if (j=0) then f[i,j]:=0 else f[i,j]:=maxlongint;
                end;
                for i:=1 to k do
                begin
                        for j:=i*3 to n do
                                f[j,i]:=min(f[j-2,i-1]+sqr(a[j]-a[j-1]),f[j-1,i]);
                end;
                writeln(f[n,k]);
        end;
end.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值