题目:http://acm.hdu.edu.cn/showproblem.php?pid=1258
题意:sum n n个数,输出所有和为sum的组合,要非递增且不能重复如第三个样例:本来可以有多个50+50+50+50+50+50+25+25+25+25,但是只输出了一个
这里有两点:1~怎么输出非递增的组合。。。。由于他输入就按非递增的了。。。所以我Dfs的for()从最后一个被用的下一位开始找。。。。保证下一个数是在目前最后一个被用的数字的后面。。。
2~怎么判重,本来可以求SUM然后从低位像a+b*sum+c*sum*sum的形式Hash,但是1000^12太大了。。。,由于最多只有12个数,且每个数字最多两位,所以我想到把数字Hash成字符串然后用set来判重。。。。
代码:
#include <iostream> #include <string> #include <set> using namespace std; const int M = 100 + 10; set <string> s; int save[M]; int ans[M]; bool used[M]; int sum; int n; int flag; void Dfs(int now, int now_sum) { if (now_sum == sum) { string str; for (int i = 1; i <= now; i++)//把这些数字Hash成字符串,用来判重 { str += (ans[i] / 10) + '0'; str += ans[i] % 10 + '0'; } if (s.find(str) == s.end()) { s.insert(str); flag = 1; for (int i = 1; i <= now; i++) { printf(i == 1 ? "%d" : "+%d", ans[i]); } puts(""); } return ; } int j; for (j = n; j >= 1 && !used[j]; j--);//找最后一个被用的位置 for (int i = j + 1; i <= n; i++)//从最后一个被用的下一位开始,保证非递增 { if (!used[i] && now_sum + save[i] <= sum) { used[i] = 1; ans[now+1] = save[i]; Dfs(now + 1, now_sum + save[i]); used[i] = 0; } } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w",stdout); while (~scanf("%d%d", &sum, &n), n) { printf("Sums of %d:\n", sum); for (int i = 1; i <= n; i++) { scanf("%d", save + i); } flag = 0; memset(used, 0, sizeof(used)); s.clear(); Dfs(0, 0); if (flag == 0) { puts("NONE"); } } return 0; }