zoukankan      html  css  js  c++  java
  • UVA 11552 Fewest Flops DP

    题意:给一个正整数k和字符串s,s的长度是k的倍数,把s每k个字符分成一组,没组之间的字符可以任意重排,但组与组之间的顺序保持不变。

    任务是让重排后的新字符串s'的块最少,连续相同的字符组成一个块,比如abbbaa有三个块a、bbb、aa。

    首先每一组子串中相同的字符肯定要放在一起,然后问题就变成怎么排列这些子串中的块。

    用dp[i][fa]表示前i组且第i+1组的最左边的字符是fa+'a'的状态能得到的最少的块数

    那么状态的转移就是两层循环枚举这个第i组最左边和最右边应该放上什么字符,如果最右边和前一组的最左边一样,那么总块数就是加上(X-1)否则加上X,X表示这一组中字符的种类,也就是这一组中块的数量。

    注意当一组中只有一种字符的特殊情况。

    vector<int> g[1010];
    int n;
    int dp[1010][27];
    int f(int k,int fa)
    {
        if(dp[k][fa]>=0)return dp[k][fa];
        if(k==0)return 0;
        vector<int> &ans=g[k];
        int minn=INF;
        for(int i=0;i<ans.size();i++)
        {
            int num=(ans[i]!=fa?ans.size():(ans.size()-1));
            for(int j=0;j<ans.size();j++)
            {
                minn=min(minn,f(k-1,ans[j])+num+(j==i&&ans.size()>1?1:0));
            }
        }
        return dp[k][fa]=minn;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        for(int ca=1;ca<=t;ca++)
        {
            int k;
            char s[1100];
            scanf("%d%s",&k,s);
            n=0;
            for(int i=0;s[i]!='';i+=k)
            {
                char str[1100];
                for(int j=i;j<i+k;j++)
                    str[j-i]=s[j];
                str[k]='';
                sort(str,str+k);
                g[++n].clear();
                for(int j=0;j<k;j++)
                    if(str[j]!=str[j+1])g[n].push_back(str[j]-'a');
            }
            memset(dp,-1,sizeof(dp));
            int num=f(n,26);
            printf("%d
    ",num);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ2023: [Usaco2005 Nov]Ant Counting 数蚂蚁
    BZOJ2044: 三维导弹拦截
    BZOJ2982: combination
    Solidity(address的四个方法)
    Solidity基础
    如何搭建以太坊的私有链
    挖矿
    智能合约
    密码学
    比特币
  • 原文地址:https://www.cnblogs.com/BMan/p/3250998.html
Copyright © 2011-2022 走看看