1. 程式人生 > >部分和問題 (dfs搜尋 尺取)

部分和問題 (dfs搜尋 尺取)

                                                          部分和問題

給定整數a1, a2, a3, a4,  ..........   ,  an  ,判斷是否可以從中取出若干個數,使得他們的和恰好為k  。

1  <= n <= 20

測試資料:n = 4

                  a[] = {1,  2,  4,  7}

                  k = 13

 

這道題資料範圍較小,可以用DFS取暴力搜

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

int a[25];
int n, k;

bool dfs(int i, int sum){
	if(i == n) return sum == k;
	if(dfs(i+1, sum)) return true;
	if(dfs(i+1, sum + a[i])) return true;
	return false;
}

int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]);
	scanf("%d", &k);
	
	if(dfs(0, 0)) printf("Yes\n");
	else printf("No\n");
} 

 

 

 如果能夠組成既定的和,則打印出被選擇的數字

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

int a[25];
int n, k, cnt = 0;
int res[25];

bool dfs(int i, int sum){
	if(i == n) return sum == k;
	if(dfs(i+1, sum)) return true;
	if(dfs(i+1, sum+a[i])){
		res[cnt++] = a[i];
		return true;
	}
	return false;
}

int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]);
	scanf("%d", &k);
	
	if(dfs(0, 0)){
		printf("Yes\n");
		for(int i = 0; i < n; i++) printf("%d ", res[i]);
		printf("\n");
	}
	else printf("No\n");
	return 0;
} 

 

問題變形:一個序列中有n個數,問是否存在最小的num(選取的數字個數)使得和大於k,存在輸出  "Yes", 否則,輸出“No”。

修改:如果n的值特別大時,例如 n = 100 時,如果用DFS的話,會爆棧。所以 要用一種方式去解決這一問題。可以用尺取的方法來做

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

const int maxn = 1e6+5;

int a[maxn];
int n, k;

int main()
{
	scanf("%d%d", &n, &k);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]);
	
	int l = 0, r = 0, sum = 0, flag = 0;
	while(1){
		while(t < n&&sum < k) sum += a[r++];
		if(sum < S) break;
		res = min(res, r-l);
		sum -= a[s++];
	}
	
	if(res > n) printf("Yes\n");
	else printf("No\n");
	return 0;
}