UVa 11552 - Fewest Flops(DP,状态设计)

来源:互联网 发布:淘宝开抢是什么意思 编辑:程序博客网 时间:2024/05/16 10:07

FEWEST FLOPS

A common way to uniquely encode a string is by replacingits consecutive repeating characters (or “chunks”) by the number oftimes the character occurs followed by the character itself. Forexample, the string “aabbbaabaaaa” may be encoded as “2a3b2a1b4a”.(Note for this problem even a single character “b” is replaced by“1b”.)

Suppose we have astring S and anumber k suchthat k divides the lengthof S.Let Sbe the substringof S from 1to kSbethe substringof S from +1 to 2k, and so on. We wish to rearrange the characters ofeachblock Si independently sothat the concatenation of thosepermutations S’ has as few chunks of thesame character as possible. Output the fewest number ofchunks.

For example,let be “uuvuwwuv”and be 4.Then Sis “uuvu” and hasthree chunks, but may be rearranged to “uuuv” which has two chunks.Similarly, Smay berearranged to “vuww”. Then S’,orS1S2, is “uuuvvuww” which is 4 chunks, indeed theminimum number of chunks.

Program Input

The input begins with a linecontaining (1≤ ≤ 100), the number oftest cases. Thefollowing lines containan integer and astring S made of no morethan 1000 lowercase English alphabet letters. It is guaranteedthat k will divide thelength of S.

Program Output

For each test case, output a single line containing theminimum number of chunks after werearrangeS as describedabove.


INPUT

25 helloworld7 thefewestflops


OUTPUT

8

10


题意:输入一个正整数 k 和一个字符串 S, 字符串的长度保证为 k 的整数倍。把 S 的字符串从左至右的顺序每 k 个分成一组,每组里面的字符串可以任意重排,但组与组间的顺序不能改变。你的任务是使重排后的字符串包含的 “块”

尽量的少,每个 “块” 为连续的相同的字母。比如 uuvuwwuv 可以分为两组:uuvu 和 wwuv,第一组重排为 uuuv , 第二组重排为 vuww,连接起来就是 uuuvvuww, 包含4个 “块”。


思路:

dp[i][j]: 第 i 块以第 j 位结尾时的最小块数

对于每个单独的一块,它的chunks就是等于出现的不同字母数

第 i 块的chunks记做 chunks[i]
如果第 i-1 块的最后一位和第 i 块的第一位是一样的,那么可以合并这两个,总chunks可以减少一个


dp[i][j] = min{  如果i-1块的第k位和i块的第一位不同:dp[i-1][k]+chunks[i], 
                       如果i-1块的第k位和i块的第一位相同: dp[i-1][k]+chunks[i]-1  }


如果第 i 块的字母都相同,且第 i 块的首字母在 i-1 块中有出现,则dp[i][j] =dp[i-1][k]


<span style="font-size:18px;">#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <string>#include <algorithm>#include <queue>#include <stack>using namespace std;const int INF = 1<<29;const double PI = acos(-1.0);const double e = 2.718281828459;const double eps = 1e-8;const int MAXN = 1010;int vis[256];char s[MAXN];int dp[MAXN][MAXN];int main(){    //freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);    int Case, kk, chunk;    cin>>Case;    while(Case--)    {        cin>>kk>>s;        int len = strlen(s);        for(int i = 0; i < len/kk; i++)        {            fill(dp[i], dp[i]+kk, INF);            memset(vis, 0, sizeof(vis));            chunk = 0;            for(int j = i*kk; j <= (i+1)*kk-1; j++)            {                if(!vis[s[j]])                {                    vis[s[j]] = 1;                    chunk++;                }            }            if(!i)            {                for(int j = 0; j < kk; j++)                    dp[i][j] = chunk;                continue;            }            for(int j = 0; j < kk; j++)            {                for(int k = 0; k < kk; k++)                {   // 在第 i-1 块里面选择第 k 位的字母,作为第 i-1 块的末位,同时作为第 i 块的首位                    int front = (i-1)*kk+k;                    int rear = i*kk+j;// 在第 i 块里面选择第 j 位的字母,作为第 i 块的末位                    if(vis[s[front]] && (chunk==1||s[front]!=s[rear]))                         //第 i 块的首位和末位不可能为同个字母,除非第 i 块的所有字母都相同                        dp[i][j] = min(dp[i][j], dp[i-1][k]+chunk-1);                    else                        dp[i][j] = min(dp[i][j], dp[i-1][k]+chunk);                }            }        }        int ans = INF;        for(int i = 0; i < kk; i++)            ans = min(ans, dp[len/kk-1][i]);        cout<<ans<<endl;    }    return 0;}</span>

本文参考:http://blog.csdn.net/shuangde800/article/details/9856943#comments

0 0
原创粉丝点击