背景 Background
在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳、勇敢、善良、团结……
不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物。所以晴天小猪自告奋勇,要去采取这种药草。于是,晴天小猪的传奇故事便由此展开……
描述 Description
这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在。但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助。
山用一个三角形表示,从山顶依次向下有1段、2段、3段等山路,每一段用一个数字T(1<=T<=100)表示,代表晴天小猪在这一段山路上需要爬的时间,每一次它都可以朝左、右、左上、右上四个方向走(**注意**:在任意一层的第一段也可以走到本层的最后一段或上一层的最后一段)。
晴天小猪从山的左下角出发,目的地为山顶,即隐者的小屋。
输入格式 Input Format
第一行有一个数n(2<=n<=1000),表示山的高度。
从第二行至第n+1行,第i+1行有i个数,每个数表示晴天小猪在这一段山路上需要爬的时间。
输出格式 Output Format
一个数,即晴天小猪所需要的最短时间。
样例输入 Sample Input
5
1
2 3
4 5 6
10 1 7 8
1 1 4 5 6
样例输出 Sample Output
10
这道题的方程很好写,f[i,j]:=min{f[i-1,j],f[i-1,j-1],f[i,j-1],f[i,j+1]);
相信很多人写出这个方程后,就因为对于这个方程要用到后面的状态,就说它有后效性,其实我们仔细分析,这道题仍然符合无后效性,对样每一层,止于上一层有关,但对于每一层,我们不能只循环一次,我们用一个repeat,如果某个状态改变,那么这次层的某个状态可能也跟着改变,所以循环到搜一边后,这一层的各个点的状态没有改变而止。我把这样的dp叫暴力dp
还有一个预处理,搜每一层之前,把f[i,0]:=f[i,i]; f[i,i+1]:f[i,1];
代码:
program pig;
var
f,a:array[0..1005,0..1005] of longint;
i,j,min,n:longint;
flag:boolean;
begin
assign(input,'hill2.in');
reset(input);
assign(output,'pig.out');
rewrite(output);
readln(n);
for i:=1 to n do
for j:=1 to i do
read(a[i,j]);
fillchar(f,sizeof(f),127);
f[1,1]:=a[1,1];
for i:=2 to n do
begin
repeat
flag:=true;
f[i,0]:=f[i,i]; f[i,i+1]:=f[i,1];
for j:=1 to i do
begin
if f[i,j]>f[i,j-1]+a[i,j] then begin
flag:=false;
f[i,j]:=f[i,j-1]+a[i,j];
end;
if f[i,j]>f[i,j+1]+a[i,j] then begin
flag:=false;
f[i,j]:=f[i,j+1]+a[i,j];
end;
if f[i,j]>f[i-1,j]+a[i,j] then begin
flag:=false;
f[i,j]:=f[i-1,j]+a[i,j];
end;
if f[i,j]>f[i-1,j-1]+a[i,j] then begin
flag:=false;
f[i,j]:=f[i-1,j-1]+a[i,j];
end; end;
until flag;
end;
min:=maxlongint;
writeln(f[n,1]);
close(input);
close(output);
end.
C++
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[2000][2000],a[2000][2000];
int main()
{
int n;
memset(dp,63,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
scanf("%d",&a[i][j]);
dp[1][1]=a[1][1];
for(int i=2;i<=n;i++)
{
while(1)
{
bool flag=false;
int tmp;
dp[i][0]=dp[i][i];
dp[i][i+1]=dp[i][1];
for(int j=1;j<=i;j++)
{
tmp=min(dp[i][j],min(min(min(dp[i-1][j],dp[i-1][j-1]),dp[i][j-1]),dp[i][j+1]));
if(tmp+a[i][j]<dp[i][j])
{
dp[i][j]=tmp+a[i][j];
flag=true;
}
}
if(flag==false) break;
}
}
printf("%d",dp[n][1]);
return 0;
}