给定一个长度为偶数的字符串s,Alice和Bob轮流操作该字符串,Alice先走。初始时Alice和Bob各自有一个空字符串。
对于每次操作,从字符串中s,选择第一个元素,或者最后一个元素,移除,并添加到自己的字符串的头部。
一直都s字符串为空串,则结束该过程
最终,Alice和Bob的字符串中,字典序最小的,即为胜者。
问,如果Alice和Bob都采取明智的策略,谁最终会是胜者。如果平局,则输出Draw
因为是添加到队头,所以影响胜利的关键,是最里边的元素。
定义dp[l][r]表示操作[l,r]的子区间的胜利者,-1表示Alice,0表示平局,1表示Bob。有两种选择。
对于当前区间[l,r],假设我方选择l,对方选择了r。
其他场景,类似分析。详见代码
#include
using namespace std;
const int maxn = 2010;
//#define debug
int n;
char s[maxn];
int dp[maxn][maxn];
int cmp(char a, char b) {
if (a == b) {
return 0;
}
return a < b ? -1 : 1;
}
void solve() {
scanf("%s", s + 1);
n = strlen(s+1);
// init
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
dp[i][j] = 0;
}
}
for (int i = 1; i + 1 <= n; ++i) {
if (s[i] != s[i+1]) {
dp[i][i+1] = -1;
}
}
for (int len = 2; len <= n; len += 2) {
for (int l = 1; l + len + 1 <= n; ++l) {
int r = l + len + 1;
dp[l][r] = 1;
int res; // res表示Bob能选择的最有利(最接近1)的局面
#define CMP_LR(a, b) {\
res = -1; \
if (dp[l+1][r-1] != 0) { \
res = max(res, dp[l+1][r-1]); \
} else { \
res = max(res, cmp(s[a], s[b])); \
} \
}
// choose l
CMP_LR(l, r)
if (dp[l+2][r] != 0) {
res = max(res, dp[l+2][r]);
} else {
res = max(res, cmp(s[l], s[l+1]));
}
dp[l][r] = res;
// choose r
CMP_LR(r, l)
if (dp[l][r-2] != 0) {
res = max(res, dp[l][r-2]);
} else {
res = max(res, cmp(s[r], s[r-1]));
}
dp[l][r] = min(dp[l][r], res);// dp[l][r]是Alice最有利(最接近-1)的局面
}
}
if (dp[1][n] == 0) {
printf("Draw\n");
} else {
printf("%s\n", dp[1][n] == -1 ? "Alice" : "Bob");
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
}
对方正在debug