uva11552

题目大意:
给出一个数字k和一串字符,k个字母为一个子串,连续的相同的字母组成一个chunks,求字符串中最少的chunks个数。

思路:
DP。
dp[i][j]表示的第i个子串中第j个字母作为最后一个字母最少可以有多少个chunks.
当第i-1个字串中出现了与第i个字串中相同的字母并且第i个字串只有一个chunks或者第i个子串的最后一个字母跟第i-1个字串的最后一个字母不相等的话,那么
dp[i][j] = min(dp[i][j],dp[i - 1][k] + chunks - 1);
否则
dp[i][j] = min(dp[i][j],dp[i - 1][k] + chunks);

代码:

#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>

char str[1005];
const int INF =0x3f3f3f3f;
int dp[1010][1010];
bool vis[130];//注意vis数组的大小。。因为这个问题错了还不知道在哪里错了。。

int main() {
    int T;
    int k;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&k);
        scanf("%s",str);
        int len = strlen(str);
        memset(dp,INF,sizeof(dp));
        for(int i = 0 ; i < len/ k; i++) {
            int chunks = 0;
            memset(vis,0,sizeof(vis));
            for(int j = i * k; j <=(i+ 1)*k - 1; j++)//第i块有哪些字母
                vis[str[j]] = true;
            for(int j = 'a'; j <= 'z'; j++)//计算出不同的字母个数
                if(vis[j])
                     ++chunks;
            if(i == 0) {//如果是第一块的话那么以每一个字母结尾都是chunks
                for(int j = 0; j <k ;j++)
                    dp[i][j] = chunks;
                continue;
            }
                for(int j = 0; j < k; j++) {
                    int rear = i * k + j;//枚举第i块中的所有字母
                    for(int p = 0; p < k; p++) {
                        int pre = (i-1) * k + p;//枚举第i - 1块中所有的字母
                        if(vis[str[pre]] && (chunks == 1 || str[pre] != str[rear]))//如果i - 1块中的字母在i中出现过而且i的不同字母个数只有一个或者i最后一个字母不合i - 1的最后一个字母相等的话那么就可以有相同的块就可以减1
                            dp[i][j] = min(dp[i][j],dp[i - 1][p] + chunks - 1);
                        else
                            dp[i][j] = min(dp[i][j],dp[i - 1][p] + chunks);
                    }
                }
        }
        int ans = INF;
        for(int i = 0; i < k; i ++) {
            ans = min(ans,dp[len / k - 1][i]);
            //printf("%d ",dp[len / k - 1][i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(uva11552)