背景 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;
}