本文最后更新于 about 5 years ago,文中所描述的信息可能已发生改变。
个人思路仅供参考,如有不足欢迎交流。
【问题描述】 
给定一个由n个小写字母组成的字符串s,需要使用最少数量的钱币来压缩它。
压缩该字符串,必须将s表示为多个相互连接的非空字符串: s=t1t2…tk,其中第 i 个字符串按照下列两种方法之一编码:
如果|ti|=1,也就是说 ti为单个字符组成的字符串,编码时需要支付a个钱币
如果ti是t1t2…ti-1的子串,编码时需要支付b个钱币
你的任务是计算压缩给定的字符串需要花费的最小钱币数。
【输入形式】 
输入的第一行包含3个用空格分隔的正整数:n、a和b(1≤n、a、b≤5000),第二行为一个长度为n的小写字符串。
【输出形式】 
输出一个整数,表示你需要为压缩s所需要支付的最小钱币数。
【样例】 
【样例输入1】 
cpp
3 3 1
aba【样例输出1】 
cpp
7【样例输入2】 
cpp
4 1 1
abcd【样例输出2】 
cpp
4【样例输入3】 
cpp
4 10 1
aaaa【样例输出3】 
cpp
12【提交代码】 
(10/10分,C++)
cpp
//23.字符串压缩
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int n, a, b;//字符串长度、a、b
    string str, sa = "", sb = "";//字符串、t(1)t(2)……t(i-1)、t(i)
    int sumMin = 0;//所用最少钱币数
    cin >> n >> a >> b;
    cin >> str;
    sumMin += a;//第一个字母一定要用a个钱币
    for (int k = 1; k < n; k++)
    {
        bool flag = false;//t(i)是否能作为t(1)t(2)……t(i-1)的子串
        sa = str.substr(0, k);//获取sa:t(1)t(2)……t(i-1)
        for (int j = 1; j < n; j++)
        {
            sb = str.substr(k, n - j);//sb:t(i)从最长的可能情况开始
            if (sa.find(sb) != string::npos)//sb是sa的子串
            {
                int len = sb.length();
                if (len >= b / a)//保证将sb作为一个字符串所用钱币比拆成单个所用钱币少
                {
                    sumMin += b;
                    flag = true;
                    k += (n - j - 1);//t(1)t(2)……t(i-1)的长度加上t(i)的长度,k++之后还会+1,所以在这里提前-1
                    break;
                }
            }
        }
        if (flag == false)
        {
            sumMin += a;
        }
    }
    cout << sumMin << endl;
    return 0;
}