Description
链接:https://ac.nowcoder.com/acm/problem/19884
来源:牛客网
在一个1行N列(N是奇数)的棋盘上,有K个格子是红色的。这种情况下,你有一个跳棋在最左端的格子上。你的目标是将它移动到最右边的格子,在开始移动之间,你可以在棋盘的任意空位上放棋子。在游戏开始后 你只可以随时在一个红色格子上放棋子。棋子的移动规则是:每次只可以选择一个棋子,跳过与之相邻的棋子走到后面的空格上,被它跳过的棋子被吃掉,即从棋盘上移走,如相邻棋子的另一侧有棋子,则不能跳。
请回答以下两个问题:
1:移动开始前至少要放多少棋子才能完成任务。
2:如果要使开始前放的棋子数要求尽量少,那么在移动过程中最少需要放多少个棋子才能完成任务。
关于规则的补充说明:
1:只能往空位上放棋子,不管是移动开始前还是移动过程中。
2:移动前棋盘最左端的那个原始棋子绝对不能被吃掉.
Solution
分类讨论
没有出现两个红色的格子相邻的情况
在每个偶数的位置放置棋子,能以最少的代价到达终点。出现了两个红色的格子相邻的情况
考虑以下图片:
可以通过两个红色的格子无限延伸,所以第一问的答案为0
第二问我们可以动态规划解决:
令为到达
点的最小代价
由于可以往前跳和往后跳,所以
时间复杂度
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
ll dp[1005];
int a[1005], cnt[1005];
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int n; cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
a[1] = 0; // 第一个点是红是白没有区别,不能影响后续判断
bool flag = false;
for(int i = 1; i <= n; i++) {
if(i % 2 == 0) cnt[a[i]]++;
if(a[i] + a[i - 1] == 2) {
flag = true;
}
}
if(!flag) {
cout << cnt[0] << '\n';
cout << cnt[1] << '\n';
} else {
cout << 0 << '\n'; // 有两个连续的1 可以交替跳
for(int i = 1; i <= n; i++) {
if(a[i]) dp[i] = 1;
else dp[i] = 1e18;
}
for(int i = 1; i <= n; i++) {
for(int j = i - 2; j >= 1; j--) {
dp[j] = min(dp[j], dp[j + 1] + dp[j + 2]);
}
for(int j = i + 2; j <= n; j++) {
dp[j] = min(dp[j], dp[j - 1] + dp[j - 2]);
}
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
if(i % 2 == 0) {
ans += dp[i];
}
}
cout << ans << '\n';
}
return 0;
} 
京公网安备 11010502036488号