第二行n個整數,用空格隔開。
第三行一個整數T,表示要達到的和。
若有多組解,優先輸出不包含第n個整數的;若都包含或都不包含,優先輸出不包含第n-1個整數的,依次類推。
最後一行輸出總方案數。
-7 -3 -2 5 9
0
-7 -2 9
2
T<=maxlongint
集合中任意元素的和都不超過long的範圍
分析:1.這道題的主題思想就是深搜(DFS),一個數字要沒選,要麼不選,那麼一個數就可以分出兩個分支,就這樣遞歸下去,枚舉出每一種情況。 2.而且設置了輸出順序,也就是從左往右,越靠後的數字權重越大,只要含有權重大的數,如上面的-3 -2 5,-7 -2 9,因爲後面那組數包含了9,所以權重更大,那麼後面那組數必須排在後面。
所以綜上所述,不僅要深搜,而且還要找個排序方法。
當時看到過有倒着搜索的解題方法,但是理解起來相對複雜,不容易理解。
當時就想到了把一組和爲T的數放進鏈表,再把鏈表放進一個對象中捆綁儲存(這個對象包含了本組數的字符序列,也就是一個字符串,還有本組數的權重和,score),我們只要把字符序列中的值所對應的權重相加在一起,就知道了本組合格的數的權重和,再根據權重和進行排序,小的在前,大的在後,輕鬆的解決了排序問題,不需要做什麼倒序搜索之類的。
import java.util.Scanner;
import java.util.PriorityQueue;
public class Main {
static class Tuple implements Comparable<Tuple> { //實現一個Comparable接口,用來比較每個和爲T對象的權重大小
int score; //儲存和爲T的權重和
String data; //儲存本組數
public Tuple(int score, String data) {
this.score = score;
this.data = data;
}
@Override
public int compareTo(Tuple o) {
return score - o.score;
}
};
static PriorityQueue<Tuple> result = new PriorityQueue<Tuple>();
//優先級隊列的好處是自動會調用Comparable的接口實現比較大小,而且效率較高,使代碼更簡潔。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int a[] = new int[n]; //輸入的數組
int b[] = new int[n]; //用來遞歸的數組
for (int i = 0; i < n; i++) {
a[i] = input.nextInt();
}
int sum = input.nextInt();
dfs(0, a, b, n, sum);//遍歷起點
for (Tuple tuple : result) {
System.out.println(tuple.data);//直接遍歷 輸出和爲T字符串
}
System.out.println(result.size());//輸出符合題目的數組數量
}
public static void dfs(int now, int a[], int b[], int n, int sum) {
if (now == n) {//噹噹前值now等於數組長度時 說明已經到底 可以進行判斷了
int temp = 0;
for (int i = 0; i < n; i++) {
if(b[i]!=-8888)//跳過識別碼-8888
temp += b[i];
}
if (temp == sum) {
StringBuilder sb = new StringBuilder();//可變的字符序列
int score = 0;
for (int i = 0; i < n; i++) {
if(b[i]!=-8888) {//例如 1 -8888 2 -8888 3
sb.append(b[i]).append(" ");
score += (1 << i);//使用的進位符 也就是二進制
//當遇到-8888時跳過 那麼1的權重爲1 2的權重爲4 3的權重爲16 加起來就是權重和
//保證後一個數 要比前面加起來總和還要大 才能保證正確
}
}
if (score > 0)//排除所有數都沒有選 全是-8888 但是相加爲0 如果sum也是0 那麼也會輸出 所以排除權重和爲零的情況
result.add(new Tuple(score, sb.toString()));//符合的,收入一個對象,每個對象又會放入優先級隊列
}
return;
}
b[now] = a[now]; //模擬選擇了這個數
dfs(now + 1, a, b, n, sum);//進入遞歸函數
b[now] = -8888; //模擬沒有選擇這個數 相當於一個識別碼 如果直接傳入0作爲不選的話 雖然理解起來方便,但是會跟其他數據衝突
dfs(now + 1, a, b, n, sum);
}
}
注:這個代碼只能得到90分,但是我看到輸入,和輸出。跟別人的100代碼比較,輸出是完全一樣的,那第九個測試數據不知道爲什麼不對。
第九組數據:
22
1 -1 2 -2 4 -4 8 -8 16 -16 32 -32 64 -64 128 -128 256 -512 512 -1024 -256 1024
0
和爲T的個數有 2047 個。