POJ-4004:数字组合(用位移方法解组合数问题,Java版)
概述:
? ? 看完題目大家應該就會想到這題可以用一個組合數的思路去編寫代碼。也就是說我們從給出的一個數組中去隨機地抽取中若干個數相加,相加的和要等于給出的那個數。雖然大致思想是沒錯了,但是,具體的思路是怎么樣的呢?
思路分析:
? ? 我們是不是會有一種通用的方法來得到一維數組,用來告訴計算機,這個一維數組的某一個位置是我要選取的數呢?
可能大家都會想到的是遞歸,不過我一個朋友給了我另一個思路,那就是用位移來解決這個問題。為什么用位移,因為快!
? ? 這里面有一個小技巧,那就是1<<n是等于2的n次方(例如1<<5 = 32)。也就是說把1左移n位,這里會得到一個結果,這個結果就是我們這個一維數組全部的子集,也就是全部的組合數。
? ? 其實如果你了解數字在計算機中的存儲和遞增過程,那么你就會得到一個有趣的結論,那就是我從0(空集)到1<<n這些數代表的就是我們要告訴計算機在那些位上是我們需要留下的,那些位上的數是我們不需要的。關于數字在計算機中的存儲和遞增過程這里不作講解。有興趣的朋友可以去查閱相關資料。
? ? 以上只是得到了全部的組合數。而他們也都是單個數字代表的,那我們能不能通過某種操作或是計算來獲得一個標志數組或是某他的什么東西來說明,當前數組的第i位是需要的呢?因為單是一個數字代表的某種組合還不能讓計算機完全理解,我們需要的是哪個位置的值。
下面我們假設有一個數字5,那我們應該怎么得到這個數字5所代表的組合呢?
| 0 | 1 | 0 | 1 |
| 0 | 0 | 0 | 1 |
我們現在假設題目中告訴我們的是只有4個數。
那么,我們先得到a&1的值(&是位且操作符,它的作用是當兩個數的每個二進制位的值都是1時,該位的值才是1,。。。。。。。想知道具體的,請查閱資料)。
這樣,我們由第一個表格就可以得到一個數字1,我們把它保存在b[0]中。
這時,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的位移結束。。。這時我們就得到了一個一維數組b[] = {1, 0, 1, 0};
我們可以看到它就是我們的a的二進制的逆序,如果你不喜歡逆序,那就用自己的方式獲得正序的數組。
關于a的位移關鍵代碼:
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;/*** 通過位移得到一個組合數的一維數組* @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;}/*** 得到某個bit數組所對應的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;}/*** 得到整個數組中共有多少個這樣的組合數* @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));} }
這里再給出我另一篇博客,《用遞歸和位移進行枚舉子集合》這里是介紹了用遞歸和位移兩種方法進行枚舉子集合的過程,感興趣的朋友可以去看看。。。
點擊連接進行查看。
總結
以上是生活随笔為你收集整理的POJ-4004:数字组合(用位移方法解组合数问题,Java版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ-2746:约瑟夫问题(Java版
- 下一篇: Java读取指定路径下的文件列表