UVA 11552 Fewest Flops 【区间dp】

题意:将一个字符串分成若干块,每块大小为k,保证串的长度是k的倍数。

每块的元素可以任意摆放,但是块与块之间的位置不变。摆放完后,将连续相同的字符看成一个,问最少多少个。

分析:定义dp[i][j]为第i块以该块的第j个元素结尾。

状态转移:

dp[i][j]=min(dp[i][j],dp[i-1][p]+cnt-1);//如果前一块以p结尾,而第i块不以p结尾,那么这里就可以合并一种字符。

dp[i][j]=min(dp[i][j],dp[i-1][p]+cnt);//其他不能合并情况。

cnt是当前字符种数。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 1005
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int dp[Mn][Mn];
int vis[30];
int main() {
    int t;
    string s;
    scanf("%d",&t);
    while(t--) {
        int k;
        scanf("%d",&k);
        cin>>s;
        CLR(dp,0x3f);
        int block=s.size()/k;
        for(int i=0;i<block;i++) {
            CLR(vis,0);
            int cnt=0;
            for(int j=i*k;j<(i+1)*k;j++) vis[s[j]-'a']=1;
            for(int j=0;j<26;j++) if(vis[j]) cnt++;
            if(!i) for(int j=0;j<k;j++) dp[i][j]=cnt;
            else for(int j=0;j<k;j++) {
                    for(int p=0;p<k;p++) {
                        if(vis[s[(i-1)*k+p]-'a']&&(s[i*k+j]!=s[(i-1)*k+p]||cnt==1))
                            dp[i][j]=min(dp[i][j],dp[i-1][p]+cnt-1);
                        else dp[i][j]=min(dp[i][j],dp[i-1][p]+cnt);
                }
            }
        }
        int ans=INF;
        for(int i=0;i<k;i++) ans=min(dp[block-1][i],ans);
        cout<<ans<<endl;
    }
    return 0;
}


你可能感兴趣的:(UVA 11552 Fewest Flops 【区间dp】)