子集和問題
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
子集和問題的一個實例爲〈S,t〉。其中,S={ x1 , x2 ,…,xn }是一個正整數的集合,c是一個正整數。子集和問題判定是否存在S的一個子集S1,使得:
。
試設計一個解子集和問題的回溯法。
對於給定的正整數的集合S={ x1 , x2 ,…,xn }和正整數c,計算S 的一個子集S1,使得:
。
Input
輸入數據的第1 行有2 個正整數n 和c(n≤10000,c≤10000000),n 表示S 的大小,c是子集和的目標值。接下來的1 行中,有n個正整數,表示集合S中的元素。
Output
將子集和問題的解輸出。當問題無解時,輸出“No Solution!”。
Sample Input
5 10
2 2 6 5 4
Sample Output
2 2 6
幫助自己理解,跑一邊例題,可能我太笨啦,個人理解,不確定對哈
輸入之後,進行sum是否小於C的判讀。flag = 0,接下來dfs(0),進入dfs函數
dfs(0):if循環,v[0] = 0且c - a[0] >= 0;c = c - a[i] = 10 - 2 = 8;
v[0]被標記,ans[0] = 2存入。
else dfs(1),類似,c = 8 - 2 = 6;v[1]標記,ans[1] = 2記錄下來,
繼續else dfs(3),c = 6 - 6 = 0;v[2]標記,ans[2] = 6記錄,c == 0滿足,
有因爲flag = 0,直接輸出print(2);flag = 0,return;結束。
介於此處並沒有體現出回溯這一步,那我們就換個例子,2 2 9 6 5,再來一次
2 2 一樣,直接到9,c = 6 - 9 < 0,進不去循環,還是例子不對,2 2 5 6 2試試,c = 6 - 5 = 1,下一步dfs(3),c - 6 和c - 2都小於0,所以,回到dfs(2)......後續更新哈哈,先不想了
接下來看代碼,我在測試過程中發現很多的代碼是無用的,所以對代碼進行刪減,刪減和備註的代碼在下面
#include<bits/stdc++.h>
using namespace std;
int v[101000];
int a[1000001],ans[1000001];
int c, n, flag;
void print(int x)
{
for(int i = 0; i <= x; i++)///注意i <= x;
cout<<ans[i]<<" ";
cout<<endl;
}
void dfs(int x)
{
for(int i = 0; i < n; i++)
{
if(v[i] == 0 && c - a[i] >= 0)
{
c = c - a[i];
v[i] = 1;
ans[x] = a[i];
if(c == 0)
{
if(flag == 0)///判斷
print(x);
flag = 1;
return;
}
else
dfs(x + 1);
v[i] = 0;
c += a[i];
}
}
}
int main()
{
while(cin>>n>>c)
{
int sum = 0;
for(int i = 0; i < n; i++)
{
cin>>a[i];
sum += a[i];
}
if(sum < c)
{
cout<<"No Solution!"<<endl;///輸出被弄錯了
break;
}
memset(v, 0, sizeof(v));
memset(ans, 0, sizeof(ans));
flag = 0;
dfs(0);
if(flag == 0)
cout<<"No Solution!"<<endl;
}
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a[10000];///輸入數組
int v[10000];///標記訪問
int ans[10000];///ans是記錄數組
int c, n, flag;
void print(int x)
{
for(int i = 0; i <= x; i++)
cout<<ans[i]<<" ";
cout<<endl;
///return;
}
void dfs(int x)
{
///if(flag == 1) return;
for(int i = 0; i < n; i++)
{
if(v[i] == 0 && c - a[i] >= 0)
{
///if(flag == 1) return;
c -= a[i];///用c減去每個數,其實就是幾個數之和等於c
v[i] = 1;
ans[x] = a[i];///ans是記錄數組
if(c == 0)///如果找到一組解,直接輸出,完成任務
{
if(flag == 0)
print(x);
flag = 1;
return;
}
else
dfs(x + 1);
if(flag == 1) return;
v[i] = 0;///回溯一步
c += a[i];
}
}
}
int main()
{
while(cin>>n>>c)
{
int sum = 0;
for(int i = 0; i < n; i++)
{
cin>>a[i];
sum += a[i];
}
if(sum < c)///如果所有的數加起來都小於c,那麼不可能有解
{
cout<<"No Solution!"<<endl;
break;
}
memset(v, 0, sizeof(v));
memset(ans, 0, sizeof(ans));
flag = 0;
dfs(0);
if(flag == 0)
cout<<"No Solution!"<<endl;
}
}