原题链接
题目翻译中的错误及补充
输入格式
输入包含多组数据,每组数据占一行。一组数据中包含若干个以空格隔开的整数,以 0 0 0 结尾。最后有一行一个单独的 0 0 0,表示数据输入完毕。
输出格式
对于每一组数据,输出一行表示答案。
样例输入
1 2 3 4 1 2 3 3 4 2 0
1 4 3 4 3 2 3 2 1 0
0
样例输出
22
18
箭头的布局应为:
思路
容易看出是 dp
。用 d p i , j ( j ∈ { 0 , 1 , 2 , 3 , 4 } ) dp_{i,j}(j\in\{0,1,2,3,4\}) dpi,j(j∈{0,1,2,3,4}) 表示到了第 i i i 个箭头,除了踩在 a i a_i ai(箭头所示位置)上的脚之外另一只脚踩在 j j j 的位置。转移时分类讨论(用 i i i 更新 i + 1 i+1 i+1):
- 踩在 a i a_i ai 上的脚刚好在 a i + 1 a_{i+1} ai+1 上,再踩一次,耗费 1 1 1 点体力。
- 踩在 j j j 上的脚刚好在 a i + 1 a_{i+1} ai+1 上,再踩一次,耗费 1 1 1 点体力。
- 移动踩在 a i a_i ai 上的脚去踩 a i + 1 a_{i+1} ai+1。
- 移动踩在 j j j 上的脚去踩 a i + 1 a_{i+1} ai+1。
为了计算一个位置到另一个位置的体力耗费,我使用了 cal
函数计算,cal
同样要分类讨论:
- 从 0 0 0 到其他位置: 2 2 2。
- 从 x x x 到 x + 1 x+1 x+1 或者从 4 4 4 到 1 1 1,从 1 1 1 到 4 4 4: 3 3 3。
- 其他情况: 4 4 4。
转移方程:
{ d p i + 1 , j = min ( d p i + 1 , j , d p i , j + 1 ) a i = a i + 1 d p i + 1 , a i = min ( d p i + 1 , a i , d p i , j + 1 ) j = a i + 1 d p i + 1 , j = min ( d p i + 1 , j , d p i , j + c a l ( a i , a i + 1 ) ) , d p i + 1 , a i = min ( d p i + 1 , a i , d p i , j + c a l ( j , a i + 1 ) ) a i ≠ a i + 1 且 j ≠ a i + 1 \begin{cases} dp_{i+1,j}=\min(dp_{i+1,j},dp_{i,j}+1) \quad a_i=a_{i+1}\\ dp_{i+1,a_i}=\min(dp_{i+1,a_i},dp_{i,j}+1)\quad j=a_{i+1}\\ dp_{i+1,j}=\min(dp_{i+1,j},dp_{i,j}+cal(a_i,a_{i+1})),dp_{i+1,a_i}=\min(dp_{i+1,a_i},dp_{i,j}+cal(j,a_{i+1}))\quad a_i \neq a_{i+1} 且 j\neq a_{i+1} \end{cases} ⎩ ⎨ ⎧dpi+1,j=min(dpi+1,j,dpi,j+1)ai=ai+1dpi+1,ai=min(dpi+1,ai,dpi,j+1)j=ai+1dpi+1,j=min(dpi+1,j,dpi,j+cal(ai,ai+1)),dpi+1,ai=min(dpi+1,ai,dpi,j+cal(j,ai+1))ai=ai+1且j=ai+1
边界情况: d p 0 , 0 = 0 , a 0 = 0 dp_{0,0}=0,a_0=0 dp0,0=0,a0=0。这样就把初始状态设为了站在 0 , 0 0,0 0,0。
答案: min d p t o t , i ( i ∈ { 0 , 1 , 2 , 3 , 4 } ) \min dp_{tot,i}(i\in\{0,1,2,3,4\}) mindptot,i(i∈{0,1,2,3,4}), t o t tot tot 表示箭头个数。
注意:每组数据要把 d p i , j dp_{i,j} dpi,j 重新设为 0x3f3f3f3f
; t o t tot tot 设为 0 0 0,重新开始统计箭头个数。
代码
#include<bits/stdc++.h>
using namespace std;
int tot,a[100005],dp[100005][5];
int cal(int x,int y){if(x==0||y==0) return 2;if(abs(x-y)==1) return 3;if(x==1&&y==4||x==4&&y==1) return 3;return 4;
}
int main(){while(1){tot=0;cin>>a[++tot];if(a[tot]==0) break;while(cin>>a[++tot])if(a[tot]==0){tot--;break;}memset(dp,0x3f,sizeof(dp));dp[0][0]=0;for(int i=0;i<tot;i++)for(int j=0;j<=4;j++){if(a[i+1]==a[i]) dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1);else if(a[i+1]==j) dp[i+1][a[i]]=min(dp[i+1][a[i]],dp[i][j]+1);else{dp[i+1][j]=min(dp[i+1][j],dp[i][j]+cal(a[i],a[i+1]));dp[i+1][a[i]]=min(dp[i+1][a[i]],dp[i][j]+cal(j,a[i+1]));}}cout<<min(min(min(dp[tot][1],dp[tot][2]),min(dp[tot][3],dp[tot][4])),dp[tot][0])<<endl;}return 0;
}