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
For example,let
Program Input
The input begins with a linecontaining
Program Output
For each test case, output a single line containing theminimum number of chunks after werearrangeS
INPUT
2
5 helloworld
7 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