UVA11552------FEWEST FLOPS------区间型的DP

题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2547

题目意思:

给你一个字符串,长度为k的整数倍,要你分成每个长度的段

每个段内可以重新编排

连续的几个字母看作一个块

问最少有几个块

解题思路:

对于每个段来说,我们可以知道最少的块,即里面有几种字母,记为chunk[i]

我们设f[i][j]为第i段的第j位放在最末尾时的最少块数

则针对第i-1块的第l个放在末尾时来说

如果和第i的第一个相同,则可以合并一个块,则

f[i][j] = min(f[i][j],f[i-1][l]+chunk-1);

否则

f[i][j] = min(f[i][j],f[i-1][l]+chunk);

 

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;



const int maxn = 1010;



int f[maxn][maxn];

char s[maxn];

bool vis[maxn];



int main()

{

    int t;

    scanf("%d",&t);

    while(t--)

    {

        int k,len;

        scanf("%d",&k);

        scanf("%s",s);

        len = strlen(s);

        memset(f,0x3f3f3f3f,sizeof(f));

        for(int i=1;i<=len/k;i++)

        {

            memset(vis,false,sizeof(vis));

            for(int j=1;j<=k;j++)

            {

                vis[s[(i-1)*k+j-1]] = true;

            }

            int chunk = 0;

            for(int j='a';j<='z';j++)

                if(vis[j])

                    chunk++;

            if(i==1)

            {

                for(int j=1;j<=k;j++)

                    f[1][j] = chunk;

                continue;

            }



            for(int j=1;j<=k;j++)

            {

                int rear = (i-1)*k+j-1;

                for(int l=1;l<=k;l++)

                {

                    int pre = (i-2)*k+l-1;

                    if(vis[s[pre]] && (chunk==1 || s[pre]!=s[rear]))

                        f[i][j] = min(f[i][j],f[i-1][l]+chunk-1);

                    else

                        f[i][j] = min(f[i][j],f[i-1][l]+chunk);

                }

            }

        }



        int ans = 0x3f3f3f3f;

        for(int i=1;i<=k;i++)

            ans = min(ans,f[len/k][i]);

        printf("%d\n",ans);

    }

    return 0;

}








 


 

你可能感兴趣的:(uva)