3900 交換茸角

2021-07-30 04:53:20 字數 1344 閱讀 5075

time limit: 20 sec  

memory limit: 512 mb

submit: 165  

solved: 72 [

submit][

status][

discuss]

動物園裡有 n 頭麋鹿。每頭麋鹿有兩支茸角,每支茸角有乙個重量。然而,一旦某頭麋鹿上

兩支茸角的重量之差過大,這頭麋鹿就會失去平衡摔倒。為了不然這種悲劇發生,動物園院長決

定交換某些茸角,使得任意一頭麋鹿的兩角重量差不超過 c。然而,交換兩支茸角十分麻煩,不

僅因為茸角需要多個人來搬運,而且會給麋鹿造成痛苦。因此,你需要計算出最少交換次數,使

得任意一頭麋鹿的兩角重量差不超過 c。

注意,交換兩支茸角只能在兩頭麋鹿之間進行。因為交換同一頭麋鹿的兩支角是沒有意義的。

第一行為整數 n,c。接下來 n 行,每行兩個整數,分別表示一開始每頭麋鹿的兩角重量。

乙個數,即最少交換次數。如果無論如何也不能使每頭麋鹿平衡,輸出 -1。

3 03 32 5

2 51

對於 100% 的資料,n <= 16, c <= 1000000, 每支茸角重量不超過 1000000。

by 佚名提供 [

submit][

status][

discuss]

考慮乙個較為簡單的情形,有n只麋鹿,是否存在乙個可行解

將茸角公升序排好,貪心地想顯然是相鄰兩個茸角配為一對,如果這樣都不合法,那麼肯定沒有可行解了

可以證明,這種情形下至多n - 1次交換就能讓所有麋鹿的茸角配對完成

考慮每只麋鹿乙隻角固定,移動另乙隻角,每次拿乙個未配對的角交換到適當位置即可

那麼剩下的只需寫個狀壓dp即可,如果當前方案不夠優,自然可以由拆分成子區間完成

#include#include#include#include#include#include#include#include#define min(a,b) ((a) < (b) ? (a) : (b))

using namespace std;

const int n = 16;

const int m = (1 << n);

int n,c,a[n],b[n],d[233],f[m];

int main()

cout << (f[(1 << n) - 1] == m ? -1 : f[(1 << n) - 1]) << endl;

return 0;

}

bzoj3900 交換茸角

dp i 表示讓狀態為i的鹿滿足要求的最少交換次數 不能列舉兩頭鹿交換,因為一頭鹿可能交換多次後轉移到下乙個狀態 那就列舉子集 dp i min 初始化 將i這個狀態上的麋鹿的角從小到大排序後,若相鄰的i和i 1滿足 h i 1 h i c,則dp i 鹿的個數 1,否則dp i inf 因為若有t...

bzoj3900 交換茸角

題目鏈結 看到n比較小,可以狀壓。可以先考慮什麼情況下會無法平衡。顯然就是排完序之後兩兩相鄰的不能滿足小於等於c的限制。狀態。用f i 來表示i集合中的鹿完成交換所需要的次數。預處理。無法平衡的肯定就是inf。已經平衡的是0。其他的先暫設為k 1 k是i集合中鹿的個數 然後轉移。每個集合可以由他的子...

bzoj3900 交換茸角(狀壓DP)

神題一道,入手毫無思路 還是頭一次寫這種找下界的狀壓dp,首先,n頭路,我們的最大交換次數為n 1次 因為把所有鹿的茸角打亂重新分配的話,只需要n 1次就可按照從小到大的順序完成重排 這也是差值最小的方法,但是如果這樣都不合法的話,說明這個集合沒法重排,輸出 1 好了,那麼說說怎麼優化 對於每乙個集...