题意:
你和你的朋友正在玩《真人快打11》这个游戏。你们正试图通过一个挑战塔。这个塔里有n个老板,编号从1到n,第i个老板的类型是ai。如果第i个boss是简单的,那么它的类型是ai=0,否则这个boss是困难的,其类型是ai=1。
在一个会话中,你或你的朋友可以杀死一个或两个老板(你和你的朋友都不能跳过这个会话,所以在一个会话中杀死的老板的最低数量是至少一个)。在你的朋友环节之后,你的环节开始,然后你的朋友环节再次开始,你的环节开始,以此类推。第一个环节是你朋友的环节。
你的朋友需要变得很好,因为他实际上无法杀死困难的老板。为了杀死他们,他使用跳过点。一个跳过点可以用来杀死一个困难的老板。
你的任务是找出你的朋友需要使用的最少的跳过点,以便你和你的朋友按照给定的顺序杀死所有n个老板。
例如:假设n=8,a=[1,0,1,1,0,1,1]。那么最好的行动方案是如下。
你的朋友杀了两个第一个老板,对第一个老板使用一个跳点。
你杀了第三个和第四个老板。
你的朋友杀了第五个老板。
你杀了第六个和第七个老板。
你的朋友杀死了最后一个老板,使用了一个跳过点,所以用两个跳过点完成了塔。
你必须回答t个独立的测试案例。
输入
输入的第一行包含一个整数t(1≤t≤2⋅104)--测试案例的数量。接着是t个测试用例。
测试用例的第一行包含一个整数n(1≤n≤2⋅105)--老板的数量。测试用例的第二行包含n个整数a1,a2,...,an(0≤ai≤1),其中ai是第i个老板的类型。
保证n的总和不超过2⋅105(∑n≤2⋅105)。
输出
对于每个测试案例,打印答案:你的朋友需要使用的最小跳过点数,以便你和你的朋友按照给定的顺序杀死所有n个老板。
例子
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
输出
2
2
2
2
1
0
题解:
对于第i个boss只有两种状态,一种是我杀(1),一直是朋友杀(0)
dp[N][2]
首先初始一下状态
因为朋友先开始杀
dp[1][0] = a[1]
第二个可能是我杀可能是他杀
dp[2][0] = a[1] + a[2]
dp[2][1] = dp[1][0](如果是我杀,无论当前是1还是0,是不需要代价的)
然后就是转移方程
dp[i][1] = min(dp[i-1][0],dp[i-2][0]) (我杀是不需要代价,从朋友转移)
dp[i][0] = min(dp[i-1][1]+a[i],dp[i-2][1]+a[i]+a[i-1])(朋友杀需要代价,从我转移)
- #include<iostream>
- #include<algorithm>
- #include<map>
- #include<queue>
- #include<vector>
- #include<cstring>
- using namespace std;
- int dp[200050][2];
- int a[200050];
- void solve()
- {
- memset(dp,0x3f,sizeof dp);
- int n;
- cin >> n;
- for(int i = 1;i <= n;i++)
- cin >> a[i];
- dp[1][0] = a[1];
- dp[2][0] = a[1] + a[2];
- dp[2][1] = dp[1][0];
- for(int i = 3;i <= n;i++)
- {
- dp[i][0] = min(dp[i-1][1]+a[i],dp[i-2][1]+a[i]+a[i-1]);
- dp[i][1] = min(dp[i-1][0],dp[i-2][0]);
- }
- cout<<min(dp[n][0],dp[n][1])<<"\n";
- }
- int main()
- {
- int t = 1;
- cin >> t;
- while(t--)
- {
- solve();
- }
- }
- //
- //