luogu P2039【[AHOI2009]跳棋】
题解 P2039 【[AHOI2009]跳棋】
这道题目首先一下子就会想到只要在编号为偶数的点上放置棋子就可以让起点的棋子调到终点了。
这里我们考虑一个非常特殊的情况,其中如果连续两个格子是红色的,那么每一个点都是可以通过这样的情况来布置。
综上所述,只要存在这样的情况就不必要再跳棋之前,放任何一颗棋子,这样就是最优秀的情况。
然后对于每一个棋子如何跳到这里,是可以直接递推得到。每一个点如果他左边或右边有了棋子,那么他就是可以直接跳到的。
- 从左向右跳
- dp[j] = min(dp[j],dp[j-1]+dp[j-2]);
- 从右向左跳
dp[j] = min(dp[j],dp[j+1]+dp[j+2]);
因此预处理一下是否存在这种情况即可。
code
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define int long long 5 const int SIZE = 1e3 + 50; 6 const int inf = 1e18 + 50; 7 8 inline int read() 9 { 10 int x = 0,f = 1; 11 char ch = getchar(); 12 while (ch < '0' || ch > '9') 13 { 14 if (ch == '-') f = -1; 15 ch = getchar(); 16 } 17 while (ch >= '0' && ch <= '9') 18 { 19 x = (x << 1) + (x << 3) + (ch ^ 48); 20 ch = getchar(); 21 } 22 return f * x; 23 } 24 25 int n; 26 int color[SIZE],dp[SIZE]; 27 bool flag; 28 29 inline void pre() // 初始化 30 { 31 printf("0\n"); 32 for (int i = 1; i <= n; ++i) 33 { 34 dp[i] = (color[i] ? 1 : inf); 35 } 36 } 37 38 inline void solve() 39 { 40 pre(); 41 for (int i = 1; i <= n; ++i) 42 { 43 if (color[i-1] + color[i] == 2) 44 { 45 for (int j = i-2; j; --j) 46 { 47 dp[j] = min(dp[j],dp[j+1]+dp[j+2]); 48 } 49 for (int j = i+1; j <= n; ++j) 50 { 51 dp[j] = min(dp[j],dp[j-1]+dp[j-2]); 52 } 53 } 54 } 55 int ans = 0; 56 for (int i = 2; i < n; i += 2) 57 { 58 ans += dp[i]; 59 } 60 printf("%lld\n",ans); 61 } 62 63 signed main() 64 { 65 n = read();flag = true; 66 for (int i = 1; i <= n; ++i) 67 { 68 color[i] = read(); 69 if (i == 1 && color[i]) color[i] = 0; 70 /*注意要把初始的点设为白色,因为初始点的颜色与答案无关,这很重要*/ 71 if (color[i] + color[i-1] == 2) flag = false; 72 } 73 if (flag) 74 { 75 int a = 0,b = 0; 76 for (int i = 2; i < n; i += 2) 77 { 78 if (color[i] == 0) a++; 79 else b++; 80 } 81 printf("%lld\n%lld\n",a,b); 82 return 0; 83 } 84 solve(); 85 return 0; 86 }

浙公网安备 33010602011771号