将一系列元素分解为最少数量的回文

时间:2016-09-27 13:16:22

标签: c++ algorithm palindrome

你将如何解决一个问题:

  

给定的整数序列可以分解成这样的部分   他们每个人都是回文。考虑序列34,45,34,56,34。   这可以分为3个回文序列,分别为34,45,34   构成第一个,56个构成第二个和34个构成   第三。它也可以在每个5个回文序列中被打破   包含一个数字。因此,可能有许多不同的方法   将给定序列分解为回文序列。我们想   确定最小数量C,使得给定序列可以   分解成C回文序列。

我的解决方案是这样的:找到阵列的最大回文(最大长度的回文),除了这个最大回文之外,取其余的数据,并尝试找到它的最大回文等,同时增加数量回文数量。

这是我到目前为止所做的:

#include <algorithm>
#include <iostream>
#include <vector>
#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;

int calc(vector<ll> A, int N) {
    int i = N;
    vector <ll> t1, t2;
    while (i >= 0) {
        t1 = vector <ll> (A.begin(), A.begin()+i);
        t2 = vector <ll> (t1.rbegin(), t1.rend());
        if (t1 == t2) return i;
        i--;
    }
    return 0;

}
int main() {
    int N;
    ll x;
    cin >> N;
    vector <ll> A(N);

    for (int i = 0; i < N; i++) {
        cin >> x;
        A[i] = x;

    }
    int temp = calc(A,N);
    int c = 0;

    while (temp != 0) {
        A = vector <ll> (A.begin()+temp, A.end());
        N = (int)A.size();
        temp = calc(A, N);
        c++;
    }
    cout << c << endl;
}

然而,我得到3个测试用例错了。稍后意识到我的程序为测试用例输出4而不是2:N = 8,{2,1,2,1,2,3,2,1}它的回文需要{2,1,2,1,2} },{3},{2},{1},而它应该是{2,1,2},{1,2,3,2,1}。如果我反转向量并计算两者之间的最小答案,我将得到正确的答案2对于此测试用例但对于Codechef上的其他人我仍然得到2个测试用例错误,可能是因为我得到错误的原因相同。

无论如何,知道如何改进这个吗?

关于codechef问题的链接:https://www.codechef.com/ZCOPRAC/problems/ZCO15001来自正在进行的比赛,但比赛只是在印度举行的Zonal Computing Olympiad的练习赛。

1 个答案:

答案 0 :(得分:1)

这是动态编程的典型问题。您可以使用O(N ^ 2)复杂度轻松解决此问题,其中N是输入字符串的大小。

首先,你可以预先计算O(N ^ 2)复杂度的所有回文,如果[i, j]中的子串O(1)是回文,那么就应该回答(让它成为你的练习)。 / p>

然后你可以计算数组dp,其中dp[i]是子串[0, i]的答案。要查找dp[i]您需要执行的操作:dp[i] = min(dp[i], dp[j] + 1)适用于所有j j < i和子串[j + 1, i]为回文结构。在这里你使用palindromes预先计算来检查[j + 1, i]中是否存在子串O(1)回文。 dp[0]当然是1

答案是dp[N - 1]

P.S。所有索引都是从0开始的。