我现在已经在几个小时内遇到了算法问题。
问题的(幻想)陈述如下:
我们的花园包含一排花。您将获得String花园中该行的当前内容。花园中的每个角色代表一朵花。不同的字符代表不同的颜色。相同颜色的花看起来都一样。您可以将花园中的花朵重新排列成您喜欢的任何顺序。 (在形式上,你可以在你的花园中交换任意两朵花,你可以任意多次这样做。)你也被给予一个与花园相同长度的字符串禁止。你想把花园重新安排成一个新的字符串G,它将满足以下条件:
没有两个相邻的花具有相同的颜色。通常,对于每个有效的i,G [i]和G [i + 1]必须不同。 对于每个有效的i,G [i]不得等于禁止[i]。 令X为满足上述所有条件的不同字符串G的数量。计算并返回数字(X模数1,000,000,007)。
只是用一个例子来澄清:X(“aaabbb”,“cccccc”)= 2(“ababab”和“bababa”)
我一直在尝试计算字符串中有多少个字母(示例中为'a' - > 3,'b' - > 4),然后递归计算不同的可能性(跳过是否有重复或禁止的信件)。这些方面的东西:
using Map = std::map < char, size_t > ;
Map hist;
std::string forbid;
size_t countRecursive(std::string s, size_t len)
{
if (len == 0)
return 1;
size_t curPos = s.size() ;
size_t count(0);
for (auto &p : hist) {
auto key = p.first;
if (hist[key] == 0) continue;
if (forbid[curPos] == key) continue;
if (curPos > 0 && s[curPos - 1] == key) continue;
hist[key]--;
count += countRecursive(s + key, len - 1);
hist[key]++;
}
return count;
}
之前初始化hist和forbid的位置。但是,这似乎是n!并且因为n可以<= 15,所以它确实在复杂性方面爆炸。
我并不是在寻找一个完整的解决方案。只是,如果你对我应该解决问题的方式有任何建议,我将非常感激!
答案 0 :(得分:0)
我接近它如下:你的'禁止'字符串和'花园'一样长。这意味着给定N个字符的字母表,每个位置G [i]最多可以有N-1个可能的字符(因为一个将被禁止)。这给你一个仅受N限制的上界。如果该界限小于模数,它可能会导致一些有趣的考虑因素,但让我们继续前进。
现在一个非常基本的方法是计算组合:如果花园长K字符,第一项G [0]将具有N-1种可能性;如果禁止[1]与G [0]不同,则第二个G [1]将具有N-2个可能性,如果禁止则为N-1 [1] == G [0]。第三个字符G [2]也有N-2种可能性,取决于禁用[2]和G [1],依此类推。
为了清楚起见:N-2来自N-1可能性的事实,必须除去另一个,即字符串中前面的字符的值,除非这个字符与当前位置的禁止字符匹配
因此,如果禁止[i + 1]总是与G [i]不同,则你有N-1 * N-2 * N-2 * ... * N-2,K次。这是你的下限。
现在在上限和下限之间有许多字符串,例如禁止[i + 1]仅对第二个位置等于G [i];第二个和第三个;所以你的字符串数量是:
N-1 * N-2 * N-2 * N-2 ... K
N-1 * N-1 * N-2 * N-2 ... K
N-1 * N-1 * N-1 * N-2 ... K
等等,直到你有一个字符串,每个字符可以有N-1种可能性。
换句话说,
N-1 * (N-2)^K-1
(N-1)^2 * (N-2)^K-2
(N-1)^3 * (N-2)^K-3
你能拥有多少个字符串?这取决于K的大小,即你的花园有多大:)
也就是说,假设我正确理解了问题。