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

来源:互联网 发布:vivo网络授权书怎么 编辑:程序博客网 时间:2024/05/01 06:10

题目地址: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;}