Gym - 101612C Consonant Fencity (暴力枚举)

版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ 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);
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/82766628
今日推荐