视频解析:[蓝桥杯]真题讲解:填充(贪心)_哔哩哔哩_bilibili
解析
对于这种多决策,且求最小值最大值问题,可以用爆搜枚举所有可能,找出合法的方案,最后在所有1合法方案中求出最大值。
假设有m个问号,每个问号都有变1或0两种选择,一共就有2^m种选择,假设m足够大,那么就会超时。
对于dfs拿不了满分的,往往有两种优解,一种是贪心,一种是dp。一般情况下贪心用于多种方案中给出一种最优策略,这种策略往往就是答案。倘若每一种策略都有反例,那就可以考虑一下dp。
对于本道题给出的贪心策略就是:
对于中间的字符而言,优先和前面的字符匹配。
比如说: 如果?号前面的1没有被匹配过,那么?号就和前面的1进行匹配,这样配下来,整个数组都是两两匹配。如果?号向后匹配,那么后面的数的选择就少了,甚至可能有元素最后没有字符匹配。
code
#include<bits/stdc++.h>
using namespace std;
int ans;
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
string s; cin >> s;
vector<bool>st(s.size()); // 用来标记当前字符是否已经被匹配
for (int i = 0; i < s.size(); i++)
{
//不是问号的情况
if (s[i]!='?')
{
//如果前一个字符存在 且和当前字符一样 且没有被匹配过
if (i - 1 >= 0 && s[i - 1] == s[i] && !st[i - 1])
{
//标记为已经匹配
st[i - 1] = true;
st[i] = true;
ans++; //方案数加1
}
else if (i+1<s.size() and s[i]==s[i+1] and !st[i])
{
st[i] = true;
st[i + 1] = true;
ans++;
}
}
else //问号的情况
{
if (st[i])continue; //没匹配过才匹配
//如果前一个字符存在 且没有被匹配过
if (i - 1 >= 0&& !st[i - 1])
{
//标记为已经匹配
st[i - 1] = true;
st[i] = true;
ans++; //方案数加1
}
else if (i + 1 < s.size() and !st[i])
{
st[i] = true;
st[i + 1] = true;
ans++;
}
}
}
cout << ans << endl;
return 0;
}