题意
有两个人闯关,第一个人先走,第二个人再走。每人最少走一步,最多走两步。给定一个01数组,当值为1的时候,第一个人需花费1块钱才可以走,否则不用花钱。第二个人随便走,不用花钱。问最少花费多少金币。
数据范围
线性
思路
显然是状态机dp。 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]表示走了前 i i i步,并且最后一步是 0 / 1 0/1 0/1走的方案中的花费最小值。状态转移方程为:
f ( i , 0 ) = m i n ( f ( i − 1 , 1 ) + a [ i ] , f ( i − 2 , 1 ) + a [ i ] + a [ i − 1 ] ) f(i,0) = min(f(i-1,1) + a[i], f(i-2,1) + a[i] + a[i-1]) f(i,0)=min(f(i−1,1)+a[i],f(i−2,1)+a[i]+a[i−1])
f ( i , 1 ) = m i n ( f ( i − 1 , 0 ) , f ( i − 2 , 0 ) ) f(i,1) = min(f(i-1,0), f(i-2,0)) f(i,1)=min(f(i−1,0),f(i−2,0))
其中要先将f数组初始化为正无穷, f ( 1 , 0 ) = a [ 1 ] , f ( 2 , 0 ) = a [ 1 ] + a [ 2 ] f(1,0) = a[1], f(2,0) = a[1] + a[2] f(1,0)=a[1],f(2,0)=a[1]+a[2]
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 200010, inf = 0x3f3f3f3f;
int n;
int a[N];
int f[N][2];
int main()
{
int T;
cin >> T;
while(T--){
cin >> n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) cin >> a[i];
f[1][0] = a[1];
f[2][0] = a[1] + a[2];
for(int i=2;i<=n;i++){
f[i][0] = min(f[i][0], min(f[i-1][1] + a[i], f[i-2][1] + a[i] + a[i-1]));
f[i][1] = min(f[i][1], min(f[i-1][0], f[i-2][0]));
}
cout << min(f[n][0], f[n][1]) << endl;
}
return 0;
}