版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82766628
题意:给你一个小写字母组成的字符串,让你把其中一些种类的字母变成大写,使得相邻的一大一小的辅音字母最多。(a,e,i,o,u,w,y为元音,其他的为辅音)
这道题我一开始感觉枚举复杂度太高,所以没敢往这个方向去想,二分图、网络流都想遍了,最后发现貌似只能枚举。。。想到枚举之后这道题就是个实实在在的水题。
我们可以把每两个字母相邻的次数用一个矩阵来表示,然后枚举所有大写字母的组合即可,每一种组合的答案是所有大写字母与所有小写字母的相邻次数,这样总的复杂度为19*19*2^19,接近1e8。我万万没想到1e8的算法居然也能过,太naive了。
用dfs动态维护答案后的复杂度可降至19*2^19,大约是1e7的水平吧。我写了两个dfs,一个用来获取最大答案,另一个用来输出解。也可以在获取最大答案的同时来保存解,但这样需要花费额外的时间,而我又懒得写状态压缩,为了防止卡掉就没有这样做。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+100;
const int M=19;
char ch[]="bcdfghjklmnpqrstvxz";
char s[N];
int vis[300],ans,G[300][300],ok[300],cur;
void dfs(int u)
{
if(u==M)
{
ans=max(ans,cur);
return;
}
dfs(u+1);
vis[ch[u]]=1;
int add=0;
for(int i=0;i<M;++i)
{
if(ch[i]==ch[u])continue;
if(vis[ch[i]])add-=G[ch[i]][ch[u]];
else add+=G[ch[i]][ch[u]];
}
cur+=add;
dfs(u+1);
cur-=add;
vis[ch[u]]=0;
}
bool dfs2(int u)
{
if(u==M)
{
if(cur==ans)return true;
else return false;
}
if(dfs2(u+1))return true;
vis[ch[u]]=1;
int add=0;
for(int i=0;i<M;++i)
{
if(ch[i]==ch[u])continue;
if(vis[ch[i]])add-=G[ch[i]][ch[u]];
else add+=G[ch[i]][ch[u]];
}
cur+=add;
if(dfs2(u+1))return true;
cur-=add;
vis[ch[u]]=0;
return false;
}
int main()
{
freopen("consonant.in","r",stdin);
freopen("consonant.out","w",stdout);
for(int i=0;i<M;++i)ok[ch[i]]=1;
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len-1;++i)
{
if(ok[s[i]]&&ok[s[i+1]])
{
G[s[i]][s[i+1]]++;
G[s[i+1]][s[i]]++;
}
}
dfs(0);
cur=0;
dfs2(0);
for(int i=0;i<len;++i)if(vis[s[i]])s[i]=toupper(s[i]);
puts(s);
}