POJ-4004:数字组合(用位移方法解组合数问题,Java版)
概述:
? ? 看完題目大家應(yīng)該就會(huì)想到這題可以用一個(gè)組合數(shù)的思路去編寫代碼。也就是說我們從給出的一個(gè)數(shù)組中去隨機(jī)地抽取中若干個(gè)數(shù)相加,相加的和要等于給出的那個(gè)數(shù)。雖然大致思想是沒錯(cuò)了,但是,具體的思路是怎么樣的呢?
思路分析:
? ? 我們是不是會(huì)有一種通用的方法來得到一維數(shù)組,用來告訴計(jì)算機(jī),這個(gè)一維數(shù)組的某一個(gè)位置是我要選取的數(shù)呢?
可能大家都會(huì)想到的是遞歸,不過我一個(gè)朋友給了我另一個(gè)思路,那就是用位移來解決這個(gè)問題。為什么用位移,因?yàn)榭?#xff01;
? ? 這里面有一個(gè)小技巧,那就是1<<n是等于2的n次方(例如1<<5 = 32)。也就是說把1左移n位,這里會(huì)得到一個(gè)結(jié)果,這個(gè)結(jié)果就是我們這個(gè)一維數(shù)組全部的子集,也就是全部的組合數(shù)。
? ? 其實(shí)如果你了解數(shù)字在計(jì)算機(jī)中的存儲(chǔ)和遞增過程,那么你就會(huì)得到一個(gè)有趣的結(jié)論,那就是我從0(空集)到1<<n這些數(shù)代表的就是我們要告訴計(jì)算機(jī)在那些位上是我們需要留下的,那些位上的數(shù)是我們不需要的。關(guān)于數(shù)字在計(jì)算機(jī)中的存儲(chǔ)和遞增過程這里不作講解。有興趣的朋友可以去查閱相關(guān)資料。
? ? 以上只是得到了全部的組合數(shù)。而他們也都是單個(gè)數(shù)字代表的,那我們能不能通過某種操作或是計(jì)算來獲得一個(gè)標(biāo)志數(shù)組或是某他的什么東西來說明,當(dāng)前數(shù)組的第i位是需要的呢?因?yàn)閱问且粋€(gè)數(shù)字代表的某種組合還不能讓計(jì)算機(jī)完全理解,我們需要的是哪個(gè)位置的值。
下面我們假設(shè)有一個(gè)數(shù)字5,那我們應(yīng)該怎么得到這個(gè)數(shù)字5所代表的組合呢?
| 0 | 1 | 0 | 1 |
| 0 | 0 | 0 | 1 |
我們現(xiàn)在假設(shè)題目中告訴我們的是只有4個(gè)數(shù)。
那么,我們先得到a&1的值(&是位且操作符,它的作用是當(dāng)兩個(gè)數(shù)的每個(gè)二進(jìn)制位的值都是1時(shí),該位的值才是1,。。。。。。。想知道具體的,請(qǐng)查閱資料)。
這樣,我們由第一個(gè)表格就可以得到一個(gè)數(shù)字1,我們把它保存在b[0]中。
這時(shí),a右移a>>1 = 0010b
| 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 1 |
a右移a>>1 = 0001
| 0 | 0 | 0 | 1 |
| 0 | 0 | 0 | 1 |
a右移a>>1 = 0000
| 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 1 |
a的位移結(jié)束。。。這時(shí)我們就得到了一個(gè)一維數(shù)組b[] = {1, 0, 1, 0};
我們可以看到它就是我們的a的二進(jìn)制的逆序,如果你不喜歡逆序,那就用自己的方式獲得正序的數(shù)組。
關(guān)于a的位移關(guān)鍵代碼:
private static int[] getBitShift(int a, int n) {int[] bit = new int[n];for (int i = 0; i < n; ++i) {bit[i] = a&1;a >>= 1;}return bit;}
import java.util.Scanner;public class Main {private static final int N = 4;/*** 通過位移得到一個(gè)組合數(shù)的一維數(shù)組* @param a* @param n* @return*/private static int[] getBitShift(int a, int n) {int[] bit = new int[n];for (int i = 0; i < n; ++i) {bit[i] = a&1;a >>= 1;}return bit;}/*** 得到某個(gè)bit數(shù)組所對(duì)應(yīng)的sum值* @param bit* @param datas* @return*/private static int getBitShiftSum(int[] bit, int[] datas) {int sum = 0;for (int i = 0; i < datas.length; i++) {if (bit[i] == 1) {sum += datas[i];}}return sum;}/*** 得到整個(gè)數(shù)組中共有多少個(gè)這樣的組合數(shù)* @param datas* @param t* @return*/private static int getCount(int[] datas, int t) {int count = 0;for (int i = 0; i < (1 << datas.length); ++i) {int[] bit = getBitShift(i, datas.length);if (getBitShiftSum(bit, datas) == t) {count++;}}return count;}public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt();int t = input.nextInt();int[] datas = new int[n];for (int i = 0; i < n; i++) {datas[i] = input.nextInt();}System.out.println("" + getCount(datas, t));} }
這里再給出我另一篇博客,《用遞歸和位移進(jìn)行枚舉子集合》這里是介紹了用遞歸和位移兩種方法進(jìn)行枚舉子集合的過程,感興趣的朋友可以去看看。。。
點(diǎn)擊連接進(jìn)行查看。
總結(jié)
以上是生活随笔為你收集整理的POJ-4004:数字组合(用位移方法解组合数问题,Java版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ-2746:约瑟夫问题(Java版
- 下一篇: POJ-2942:吃糖果