查看完整版本: 請問一題ACM(ranking prizes)
頁: [1] 2

gtoman2006new 發表於 2011-6-23 09:22 PM

請問一題ACM(ranking prizes)

本帖最後由 gtoman2006new 於 2011-6-27 10:32 PM 編輯

題目描述:
如果有N個門,每個門一開始都是關閉的,你可以打開S個門,S<N,其中第一個門有獎金100元,第二各門有獎金
200元,第j各門有獎金(2的j-1次方)*100,如第三個門有獎金 (2的3-1次方)*100=400元,題目給你三個參數(N、S、K),
N表示N個門,S表示你可以打開S各門,K表示找到第K各排名時的門狀態(打開或關閉)。
例如:
總共有四各門,你可以打開兩各門,那麼門的狀態有六個,
CCOO    COCO   COOC   OCCO   OCOC   OOCC
"C"和"O"是close和open,他們的獎金分別是 300(100+200)、500(100+400)、600(200+400)、900、1000、1200
依序排名 CCOO  COCO  COOC OCCO OCOC OOCC   1,2,3,4,5,6
如果K等於4,那麼輸出就顯示 OCCO $900

sample input

4 2 4

5 2 6

sample output
OCCO
$900

COOCC
$1200

我的想法是用位元來處理
比如有4個門,可以打開兩個門,
那麼我就產生 0011 0101 1001 0110 1010 1100這幾個數字
,這幾各數字就用 1向左shift來產生
                                        (0<<1 || 1<<1)== 0011
                                        (0<<1 ||  2<<1)== 0101
                                        (0<<1 || 3<<1)== 1001
                                                            ......
可是變成要排列組合,將每個可能的狀態,用迴圈寫成,小弟想了一下,
比如6各門可以打開3各,那麼排列組合有
012345
012 (0<<1 || 1<<1 || 2<<1)==000111
013 (0<<1 || 1<<1 || 3<<1)==001011
014 (0<<1 || 1<<1 || 4<<1)==010011
015 (0<<1 || 1<<1 || 5<<1)==100011
123 (1<<1 || 2<<1 || 3<<1)==001110
124 (1<<1 || 2<<1 || 4<<1)==010110
125 (1<<1 || 2<<1 || 5<<1)==100110
134 (1<<1 || 3<<1 || 4<<1)==011010
135 (1<<1 || 3<<1 || 5<<1)==101010
145(1<<1 || 4<<1 || 5<<1)==110010
234(2<<1 || 3<<1 || 4<<1)==011100
235(2<<1 || 3<<1 || 5<<1)==101100
245(2<<1 || 4<<1 || 5<<1)==110100
345(3<<1 || 4<<1 || 5<<1)==111000

不曉得要怎麼寫,大大有其它方式嗎。

謝謝...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><div></div>

poorpoorpoor 發表於 2011-6-23 10:03 PM

你的方向沒錯
關鍵在於若某個門打開他將會大於所有沒開的組合
例如輸入:6 3 10
有開第六道門至少有3200
沒開第六道門最多3100
有開第六道門的方法數有c(5,2)=10
所以沒開第六道門的至少是11名
而所求排名<11
可知第六道門一定有打開
再討論第五第四一直到全討論完
如此一來便求得我們所要的數

gtoman2006new 發表於 2011-6-23 10:15 PM

P大我看不懂耶
什麼意思呢???

goodbye_mylove 發表於 2011-6-23 10:50 PM

我簡化一下原po的問題好了,
他的問題事實上就是

C(m, n)  for n<m

要求一母集裡面所有可能之「組合」

gtoman2006new 發表於 2011-6-23 11:12 PM

本帖最後由 gtoman2006new 於 2011-6-25 10:15 AM 編輯

請問一下,
怎麼用迴圈來表示下面的式子,
同時也能跟隨著輸入的變化得到相對應如下的式子呢。
012345
012 (0<<1 || 1<<1 || 2<<1)==000111
013 (0<<1 || 1<<1 || 3<<1)==001011
014 (0<<1 || 1<<1 || 4<<1)==010011
015 (0<<1 || 1<<1 || 5<<1)==100011
023(0<<1 || 2<<1 || 3<<1)==001101
024(0<<1 || 2<<1 || 4<<1)==010101
025(0<<1 || 2<<1 || 5<<1)==100101
034(0<<1 || 2<<1 || 4<<1)==011001
035(0<<1 || 2<<1 || 4<<1)==101001
045(0<<1 || 2<<1 || 4<<1)==110001
123 (1<<1 || 2<<1 || 3<<1)==001110
124 (1<<1 || 2<<1 || 4<<1)==010110
125 (1<<1 || 2<<1 || 5<<1)==100110
134 (1<<1 || 3<<1 || 4<<1)==011010
135 (1<<1 || 3<<1 || 5<<1)==101010
145(1<<1 || 4<<1 || 5<<1)==110010
234(2<<1 || 3<<1 || 4<<1)==011100
235(2<<1 || 3<<1 || 5<<1)==101100
245(2<<1 || 4<<1 || 5<<1)==110100
345(3<<1 || 4<<1 || 5<<1)==111000...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><br><br><br><br><br><div></div>

goodbye_mylove 發表於 2011-6-23 11:21 PM

我自己認為用 bitwise mask 會比較麻煩,必須考慮到的一點是:
你怎知道 C(M, N),其中 M <=32 (64) ?
若 32 < M <=64,可以宣告成 unsigned long long 來做 bitwise,但速度會降慢;
若 M > 64,你想怎麼做?設 Array 再去換算嗎?我認為會比較麻煩。

類似的問題在本版已有討論過
[作業] 這個問題我不知道如何寫成C語言

請自行參閱。

abcde12101 發表於 2011-6-24 01:17 AM

本帖最後由 abcde12101 於 2011-6-24 01:52 AM 編輯


依序排名 CCOO  COCO  COOC OCCO OCOC OOCC   1,2,3,4,5,6

100+200 = 300
100+400 = 500
100+800 = 900
200+400 = 600
200+800 = 1000
400+800 = 1200
樓主好像排錯了...???

總覺得我的理解跟題目有些出入... 題目不就是要問C(N,S)裡第K個的排列嗎?


如果是這樣的話, 要是N <= 10, 我會選擇暴力... 因為太方便了!!!
http://codepad.org/Wdsr2aNr
另外是, 據說適當地運用位運算可以大幅度增加代碼的帥氣程度... ...... 所以我也稍為打扮了一下

如果N介乎, 我會選擇p大的方向, 就是排除法, 瞬間略過一票非答案的狀態. 不過因為要求得ncr的值, 所以N太大的話感覺還是做不出來...
http://codepad.org/Xb456vJV...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

gtoman2006new 發表於 2011-6-25 10:24 AM

A大,我沒排錯ㄚ,
不是下面這樣嗎??
100+200 = 300  CCOO
100+400 = 500  COCO   
200+400 = 600 COOC
100+800 = 900 OCCO
200+800 = 1000 OCOC
400+800 = 1200  OOCC

gtoman2006new 發表於 2011-6-25 10:27 AM

請問abcde12101大大
你試用什麼演算法寫的,
小弟我不是資工系,
一 些演算法都不知道,
不曉得可以交我嗎。

謝謝

abcde12101 發表於 2011-6-25 01:48 PM

本帖最後由 abcde12101 於 2011-6-25 01:50 PM 編輯

回復 8# gtoman2006new

呃, 我將O和C搞翻了... 你排得沒錯.{:1_newbiggrin:}


其實沒用到什麼有名的演算法, 第一個是深度優先搜尋, 第二個就是P大的排除法, 只不過狀態都是用位(bit)達成

因為觀察到排列都可以一一對應於一個整數值, 所以可以用整數表示一個排列的值, 不用重新計算

比方說OCCO對應於"1001", 即是1+8=9; COCO對應於"0101", 即是1+4=5.


第一個方法的概念就是對於(深度,位的狀態)進一步搜下去.
要是深度==S, 亦即已經枚舉了S個bits, 那麼這就是其中一個目標的狀態. 然後將其放進優先隊列裡面排序, 方便之後找出第K個小的值
要是深度!=S, 便先找出最右邊的bit在哪裡(state&-state便是求這個位的位置), 從那裡開始往右移, 要是能放進去(state&i==0就是說state並沒有i這個bit), 便往(depth+1,state|i)搜.(state|i是將i這個bit放進去state裡面)
初始狀態是(0,0), 亦即深度是0(從樹根開始), 位狀態是空的(一個bit都沒放進去)


第二個方法是排除法, 排除法的概念是從最左邊的bit開始, 考慮如果這個bit是1/0, 之後的狀態會比幾個數大/小

不過我的程序是找出第K個大的排列... 所以以下的話會跟我的代碼有出入

以(n,s,k)==(5,3,6)作例, 從最左的bit開始 : XXXXX
要是我們設定為0XXXX, 那麼我們還可以在4個bits裡面自由放置3個bits.
這裡面會有C(4,3)=4個排列, 所以我們只能夠搜到第1至第4個排列
要是我們設定為1XXXX, 那麼就會比所有0XXXX的排列大.

因為K==6, 所以我們不能選擇0XXXX, 因為這樣做我們只能夠找C(4,3)==4以內的排列. 我們得選擇1XXXX.
這樣, 我們就可以排除了第1至第4個排列, 將我們的範圍放到第5個以上的排列. 然後, 為了方便計算, 我會將K -= 4, 然後以同一個演算法繼續做

附上一個表, 希望你能夠理解排除法的概念... 其實跟二分搜索蠻相似的
00111
01011
01101
01110

10011
10101<-目標排列
10110

11001
11010
11100...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><br><br><br><br><br><div></div>

gtoman2006new 發表於 2011-6-26 10:30 AM

本帖最後由 gtoman2006new 於 2011-6-27 10:28 PM 編輯


謝謝abcde12101
小弟還要再想一下。
小弟用最笨的暴力法求得答案,
就是先產生所有的可能的排列,
在去排序這些排列組合,在依據k的大小,得到對應的排名。
小弟附上寫的程式碼。

謝謝

abcde12101 發表於 2011-6-26 12:52 PM

回復 11# gtoman2006new

嗯... 代碼裡面有幾個地方覺得可以加速的


印迴圈不需要用sizeof(X)/sizeof(int), 這題有寫好長度, 不需要額外花時間每次計算 而且如果調用到非常數時間的函式的話, 這樣寫就會將時間複雜度提升... 比方說用strlen()作為迴圈中止的判斷

Set可以用int而非char, 這樣做就無需要每次都減48才繼續計算... 我以前就試過忘了減48而RE了, 寫起來也比較麻煩的感覺

另外是2的次方, 位移的assignment你好像寫翻了... 應該是1<<(set-48)這樣的, 絕對會比較快...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

gtoman2006new 發表於 2011-6-26 02:33 PM

哈 謝謝  abcde12101
難怪我用位移都不行,
只好用power()去計算。

TKCS 發表於 2011-6-27 01:21 PM

謝謝大大分享解法{:1_newtoo_sad:}

gtoman2006new 發表於 2011-6-28 11:24 PM

本帖最後由 gtoman2006new 於 2011-6-28 11:28 PM 編輯

請教abcde12101大大

因為K==6, 所以我們不能選擇0XXXX, 因為這樣做我們只能夠找C(4,3)==4以內的排列. 我們得選擇1XXXX.
這樣, 我們就可以排除了第1至第4個排列, 將我們的範圍放到第5個以上的排列. 然後, 為了方便計算, 我會將K -= 4, 然後以同一個演算法繼續做
之後確定第五個bit為1,一定是1XXXX,之後考慮第四個bit 11XXX或10XXX,如果我假設第四個bit為1,那麼有C(3,1)=3個排列,假設第四個bit為0,那麼C(3,2)=3各排列,此時k=k-4=2,之後要怎麼分析呢。
另外想請問排除法的程式,我都看不懂,一開始的ncr二維陣列要做什麼用的,初始化是要做什麼呢?


附上一個表, 希望你能夠理解排除法的概念... 其實跟二分搜索蠻相似的
00111
01011
01101
01110

10011
10101<-目標排列
10110

11001
11010
11100...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><br><br><br><br><br><div></div>
頁: [1] 2