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
",ans);
    }
    return 0;
}





原文地址:https://www.cnblogs.com/riskyer/p/3270912.html