你可以解決這個貪婪。
將你的集合劃分爲S [i],其中最初S [i] = {s in S使得s%d == i}。
然後,重複選擇k(在您的示例中爲5)最大的子集S [i]並從每個子集中移除一個元素。
下面是實現這一些略微低效但簡單的代碼:
def part(S, k, d):
"Split S into subsets of size<=d, each with elements unique mod k"
parts = [[] for _ in xrange(k)]
for s in S:
parts[s % k].append(s)
while sum(len(p) for p in parts):
parts.sort(key=len, reverse=True)
yield [x.pop() for x in parts[:d] if x]
S = [12,13,15,21,22,26,6,14,27,28,29,30,39,40,4,17,25]
for s in part(S, 6, 5):
print sorted(s)
輸出此代碼,其示出了至多5大小的子集,使得沒有子集包含兩個數等於模6:
[4, 14, 25, 30, 39]
[6, 13, 17, 27, 40]
[12, 21, 26, 28, 29]
[15, 22]
parts
這種排序條件可以通過優先級隊列和運行計數器進行優化,但會掩蓋正在發生的事情。優化後的表單將在O(n log n)時間運行;因爲它是O(n^2日誌n)
[我應該說,我非常肯定這個解決方案是正確的,但我不太明白如何證明它。我很希望看到證明(或反以顯示它是錯的)
那麼,你可以蠻力吧:) – zegkljan
最有可能,你將別無選擇,只能蠻橫,因爲這比「揹包」式的問題稍微複雜一些。這些條件不一定只適用於一個元素,所以沒有辦法在不知道該特定子集的其他元素的情況下過濾出子集的潛在成員,因此在條件甚至可以被測試之前必須選擇子集(儘管%d!= 0與常數差異相矛盾)。由於找到最小數量的子集是需求,而不是找到任何匹配的子集,這將是一個非常計算密集的問題。 –
你說'd'是兩個數之間的常數差,那麼如何設置{12,13,15,22,17}'滿足這個? –