子集和问题 - 回溯&搜索
题目地址:http://www.51cpc.com/web/problem.php?id=4264
其实一看到这道题我就想到了01背包,但是卡死在了如何顺序输出;
个人人为回溯本身就会用到搜索,像是充分不必要条件的那种感觉。
试了下动规的方法,并不适用于此题,动规可以得到是否有解或求出其中一组解,但无法按输入顺序输出第一组解。
Summarize:
1. 注意特判所有元素加起来都小于C;
2. 递归内循环从0开始,由于vis不必担心重复;但题目要求顺序输出,故应从0开始;
附AC代码:
1 #include<iostream> 2 #include<cstring> 3 #define inf 1e9 4 typedef long long LL; 5 using namespace std; 6 7 const int N = 7e3+5; 8 LL n,c; 9 LL a[N], vis[N], can; 10 11 void dfs(int i, LL sum) 12 { 13 if(can || i>=n) return; 14 15 if(sum == c) 16 { 17 can=1; 18 int i=0; 19 while(!vis[i] && i<n) i++; 20 cout<<a[i]; 21 for(i++; i<n; i++) 22 if(vis[i]) cout<<' '<<a[i]; 23 cout<<endl; 24 return; 25 } 26 27 for(int k=0; k<n; k++) { 28 if(sum+a[k]<=c && !vis[k]) { 29 vis[k] = 1; 30 dfs(k, sum+a[k]); 31 vis[k] = 0; 32 } 33 } 34 } 35 36 int main() 37 { 38 ios::sync_with_stdio(false); 39 40 while(cin>>n>>c) 41 { 42 can=0; 43 LL sum=0; 44 for(int i=0; i<n; i++) { 45 cin>>a[i], vis[i]=0; 46 sum += a[i]; 47 } 48 if(sum < c) { 49 cout<<"No Solution!"<<endl; 50 continue; 51 } 52 dfs(0,0); 53 if(!can) cout<<"No Solution!"<<endl; 54 } 55 }
这里也附上动规的代码,不能AC,但仍未一种想法。
1 #include<iostream> 2 #include<stack> 3 #include<algorithm> 4 using namespace std; 5 const int MAX = 7003 6 int dp[MAX][MAX]; 7 int p[MAX]; 8 int n,m; 9 stack<int> goods; 10 11 int main() { 12 cin>>m>>n; 13 for (int i = 1; i <= m; i++) 14 cin >> p[i]; 15 for (int i = 1; i <= m; i++) { 16 for (int j = 1; j <= n; j++) { 17 dp[i][j] = (i == 1 ? 0 : dp[i - 1][j]); 18 if (j >= p[i]) { 19 dp[i][j] = max(dp[i][j], dp[i - 1][j - p[i]] + p[i]); 20 } 21 } 22 } 23 24 for (int i = m; i > 0; i--) 25 for(int j=0;j<=n;j++){ 26 if (dp[i][n] - p[i] == dp[i - 1][j]) { 27 goods.push(p[i]); 28 n = j; 29 } 30 } 31 32 cout<<goods.top(); 33 goods.pop(); 34 35 while(!goods.empty()) { 36 cout<<' '<<goods.top(); 37 goods.pop(); 38 } 39 cout<<endl; 40 return 0; 41 }