CodeVS 3415-最小和

原题

题目描述 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.
View Code

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/HAdolf-HQY/p/6289509.html