题目简述 :
给出一串 01 串,每次可向其中加入 0 或 1, 当有连续 0 或 1 的长度 ≥ 3 时,该连续串会被抵消, 求使 01 串全部抵消的最小次数。
输入简述 :
T 代表数据, T个 01 串。
输出简述 :
所有的答案。
sample input :
4
11
10101
101001001
01001101011001100
sample ouput :
1
4
3
2
PS:其实,我是真的不想水题目,情有可原啊。
题解 & 教训:
这次考试我炸的那么惨,还是没有策划好时间,先是想了一会儿的 DP, 发现没时间了,又去写搜索,又没有写出来,然后逼迫之下又开始想 DP,然后在离考试结束还有 8 分钟时我想出来了 DP,又有什么用呢,这种策略是十分不成熟的,一定要吸取教训。
这道题很明显是一个 DP 题,我们再记一个num, 表示压缩后的权值大小,我们压缩是将连续的 0 和 1 压缩成一个整数, 表示连续 0 或 1 的长度, 记
DP[i][j]
表示将 i 到 j 区间全部消掉的最小代价,于是我们可以得到转移方程 :
DP[i][j]=3−num[i](i==j)
如果 color[i]!=color[j] , 只能分成两半抵消,转移方程 :
DP[i][j]=DP[i][k]+DP[k+1][j](i≤k<j)
如果 color[i]==color[j] , 我们有种特殊的情况要讨论, 当 color[i]=color[j]=color[k] 不能直接用两半相加,因为你在抵消其中一半时,已经破坏了另一半的形式 :
DP[i][j]=DP[i+1][k−1]+DP[k+1][j−1](num[i]+num[j]<4,num[k]=1)
这样列式子主要是为了排除这样的例子 : 1100110010110100110011 答案是 3 不是 2.
而 color[i]=color[j] 有一个普通的式子 :
DP[i][j]=DP[i+1][j−1]+max(0,3−num[i]−num[j])
代码 :
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#define clr(a) memset(a, 0, sizeof(a))
using namespace std;
inline int read() {
int i = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1; ch = getchar();
}
while(isdigit(ch)) {
i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
}
return i * f;
}
const int MAXN = 200 + 5;
int dp[MAXN][MAXN], num[MAXN], c[MAXN];
inline void solve() {
memset(dp, 127, sizeof(dp));
clr(num);
char s[MAXN];
scanf("%s", s + 1);
int len = strlen(s + 1); int n = 0;
for(int i = 1; i <= len; ++i)
if(s[i] != s[i - 1]) c[++n] = s[i], num[n] = 1;
else ++num[n];
for(int i = n; i >= 1; --i)
for(int j = i; j <= n; ++j) {
if(i == j) { dp[i][j] = 3 - num[j]; continue; }
if(c[i] == c[j]) {
dp[i][j] = dp[i + 1][j - 1] + max(0, 3 - num[i] - num[j]);
if(num[i] + num[j] < 4)
for(int k = i + 2; k < j; k += 2)
if(num[k] == 1)
dp[i][j] = min(dp[i][j], dp[i + 1][k - 1] + dp[k + 1][j - 1]);
}
for(int k = i; k < j; ++k) dp[i][j] = min(dp[i][k] + dp[k + 1][j], dp[i][j]);
}
printf("%d\n", dp[1][n]);
}
int main() {
int times = read();
while(times--) {
solve();
}
}