原题链接: http://codeforces.com/contest/1418/problems
测试样例
input
6
8
1 0 1 1 0 1 1 1
5
1 1 1 1 0
7
1 1 1 1 0 0 1
6
1 1 1 1 1 1
1
1
1
0
output
2
2
2
2
1
0
题意: 有一个挑战塔,其中有层,每层都有一个BOSS,它们都具有困难程度。现在你和你的朋友联手闯关,你们都可以杀死一个或两个BOSS(杀死两个BOSS即过两关。),当你的朋友结束关卡之后,你开始下一关,接下来再你朋友进行下一关。但有一个秘密:你的朋友其实无法杀死困难程度高的BOSS,他需要使用跳跃卡。问你们通过后他至少需要使用的跳跃卡数量。
解题思路: 一道经典的dp问题。我们要找准状态,由于每一关都是层层递进的,且每一关的通关者可以是你或者你朋友。(第一关除外。)那么我们则可以用01变量来表示你朋友和你。则我们就可以找到状态了:
- 用
表示通第
关需要使用的最少通关卡,且第
关为你朋友通关。
- 用
表示通关第
关需要使用的最少通关卡,且第
关为你通关。
找准状态之后根据题意设立状态转移方程即可(一定是根据题意来建立的),OK,具体看代码。
AC代码
/*
*
*/
//POJ不支持
//i为循环变量,a为初始值,n为界限值,递增
//i为循环变量, a为初始值,n为界限值,递减。
using namespace std;
const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 2e5+5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//
int t,n,a[maxn];
int dp[maxn][2];//用0表示你朋友,1表示你自己。状态转移:用dp[i][0]表示打的第i个怪,且是你朋友打完的。dp[i][1]表示打的第i个怪,且是你打完的。
int main(){
//freopen("in.txt", "r", stdin);//提交的时候要注释掉
IOS;
while(cin>>t){
while(t--){
cin>>n;
rep(i,1,n){
cin>>a[i];
}
//初始化
memset(dp,inf,sizeof(dp));
//确定特殊情况。
dp[1][0]=a[1];
dp[2][0]=dp[1][0]+a[2];
dp[2][1]=dp[1][0];
rep(i,3,n){
//利用dp求解最小值。
dp[i][0]=min(dp[i-1][1]+a[i],dp[i-2][1]+a[i-1]+a[i]);
dp[i][1]=min(dp[i-1][0],dp[i-2][0]);
}
//最终状态有两个,求最小值即可。
cout<<min(dp[n][0],dp[n][1])<<endl;
}
}
return 0;
}