zoukankan      html  css  js  c++  java
  • [洛谷P1278]单词游戏

    题目

    Description

    Io和Ao在玩一个单词游戏。

    他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致。

    游戏可以从任何一个单词开始。

    任何单词禁止说两遍,游戏中只能使用给定词典中含有的单词。

    游戏的复杂度定义为游戏中所使用的单词长度总和。

    编写程序,求出使用一本给定的词典来玩这个游戏所能达到的游戏最大可能复杂度。

    Input

    输入文件的第一行,表示一个自然数N(1≤N≤16),N表示一本字典中包含的单词数量以下的每一行包含字典中的一个单词,每一个单词是由字母A、E、I、O和U组成的一个字符串,每个单词的长度将小于等于100,所有的单词是不一样的。。

    Output

    输出文件仅有一行,表示该游戏的最大可能复杂度。

    Sample Input

    5
    IOO
    IUUO
    AI
    OIOOI
    AOOI

    Sample Output

    16

    思路

    这是一道状压$dp$的题;

    题目可以转化为将允许使用的单词连接的最大长度(连接条件有限制);

    我们设$dp[i][k]$ 表示连到第$i$ 个单词,$k$是连接好的单词的集合,$dp[i][k]$ 就是最大长度;

    那么就可以预处理出所有单词的长度$a[i]$;

    然后判断两个单词是否可以连接$f[i][j]$;

    转移方程是: $dp[i][k]=max(dp[i][k],dp[j][k oplus (1<<(i-1))]+a[i])$

    代码

    #include<bits/stdc++.h>
    #define re register
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    ll n;
    ll a[20],f[20][20];
    char s[20][101];
    ll dp[20][1<<16];
    int main()
    {
        memset(dp,-1,sizeof(dp));
        n=read();
        for(re ll i=1;i<=n;i++)
        {
            scanf("%s",s[i]+1);//读入 
            a[i]=strlen(s[i]+1);//预处理所有单词的长度 
        }
        for(re ll i=1;i<=n;i++)
        for(re ll j=1;j<=n;j++)
        {
            ll len=strlen(s[i]+1);
            if(s[i][len]==s[j][1])
               f[i][j]=1;//判断两个单词是否可以连接 
        }
        for(re ll i=1;i<=n;i++)
            dp[i][1<<(i-1)]=a[i];//可以从每一个单词作为集合第一个数开始 
        for(re ll k=1;k<=(1<<n)-1;k++)//枚举集合状态 
        for(re ll i=1;i<=n;i++)
        {
            if(!(k&(1<<(i-1)))//判断 i 这个单词是否在集合里 
                continue;
            for(re ll j=1;j<=n;j++)
            if(f[j][i])//如果可以连 
            {
                if(i==j)//不能自己连自己 
                    continue;
                if(k&(1<<(j-1)))//j 是否在集合里 
                    dp[i][k]=max(dp[i][k],dp[j][k^(1<<(i-1))]+a[i]);//转移方程 
            }
    //        cout<<i<<" "<<k<<endl;
    //        cout<<dp[i][k]<<endl;
        }
        ll ans=-1;
        for(re ll k=1;k<=(1<<n)-1;k++)
        for(re ll i=1;i<=n;i++)
            ans=max(ans,dp[i][k]);//可以从任何一个状态或单词结束 
        printf("%lld
    ",ans);//输出ans
        //return 0; 
    }
  • 相关阅读:
    端口被占用
    启动Windows防火墙提示“0x8007042c"
    vue创建全局组件
    vue中过度动画之列表添加删除动画实现
    vue中过渡动画(类名结合动画实现方式)
    vue中过渡动画(类名实现方式)
    this.$nextTick()方法的使用
    利用axios获取数据并渲染到视图层
    axios的简单使用
    watch深度监听
  • 原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/13485447.html
Copyright © 2011-2022 走看看