原题
题目描述 Description
小浣熊松松来到文具店,选择了K支自己喜欢的水彩笔,并抄下了它们的价格。可是到结算时,他发现自己抄价格时抄得太密集,以至于所有价格连成了一个数字串(你可以假设价格都是正整数)。老板想和松松开个玩笑,于是对他说:“你可以把这个数字串分成K段,代表这K支笔的价格,然后把他们加起来,就是你要付给我的钱了。”当然,松松想尽可能省下钱去买《算法导论》,所以请你来帮忙算算,他最少需要付多少钱。
输入描述 Input Description
第一行包含一个整数N,代表松松抄下来的数字串。
第二行包含一个整数K,代表松松买了K支水彩笔。
输出描述 Output Description
输出仅一行,为松松买这些笔最少花的钱。
样例输入 Sample Input
79846
3
样例输出 Sample Output
133
数据范围及提示 Data Size & Hint
对于20%的数据,K=1;
对于100%的数据,数字串长度不超过8,K<=数字串长度。
由于是松松来划分,因此可以出现有前导0的价格,或者价格就是0。
网址:http://codevs.cn/problem/3415/
题意
给一串数字,将它分为K部分,使得这K部分加起来的和最小。
题解
这道题数据挺水,dfs和递归貌似也能过,但Code给它的标签是DP,本人也就跟着写了一下DP。
首先定义一个二维数组F,Fi,j表示数字串前i位分成j部分时的最优解。
下面给出DP状态转移方程,f[i,j]=min(f[i,j],f[k,j-1]+p(copy(s,k+1,i-k)))
具体解释:
定义一个函数p(s),表示将字符串s转为数字(原先读入的为字符串)。
接下来三重循环:
for i:=1 to length(s) do//枚举字符串长度
for j:=1 to min(n,i) do begin//枚举分的份数,但j不能大于i,因为1个数不可能被分成2份
if j=1 then f[i,j]:=copy(s,1,i) else//如果份数为1则还是它本身
for k:=1 to i-1 do f[i,j]:=min(f[i,j],f[k,j-1]+p(copy(s,k+1,i-k)));end;//在[1,i)的半开闭区间中不断更新答案找出最优解
OK下面pia代码:
1 uses math; 2 var f:array[0..10,0..10] of int64; 3 var n,l,i,j,k:longint; 4 var s:string; 5 function p(s:string):longint; 6 var num,i:longint; 7 begin 8 num:=0; 9 for i:=1 to length(s) do num:=num*10+ord(s[i])-48; 10 exit(num); 11 end; 12 begin 13 readln(s);readln(n); 14 l:=length(s); 15 for i:=1 to l do for j:=1 to n do f[i,j]:=maxlongint; 16 for i:=1 to l do 17 for j:=1 to min(i,n) do 18 begin 19 if j=1 then f[i,j]:=p(copy(s,1,i)) else 20 for k:=1 to i-1 do f[i,j]:=min(f[i,j],f[k,j-1]+p(copy(s,k+1,i-k))); 21 end; 22 writeln(f[l,n]); 23 end.
版权声明:本文为博主原创文章,未经博主允许不得转载。