数据选取
Time Limit:1000MS Memory Limit:32768K
2 32 10 3 10 5 2 6 6 8 1 9 8 76 7 9 1 10 7 3 4 8
4 -1
题目链接:http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1668
/* ---------------------------------------------------------------------------------- 题目分析:题目的意思显然易见,就是求最少个数之和恰好等于m.按照贪心思想就是,先选择 一个比较m小,但是又是在那堆数里面最大的数,然后再如此选择下一个这样的数.直到将找到和 可以恰好等于又或者找不到为止.如果找到这些数,就直接返回.如果找不到这些数,就回溯到上 一步,重新选择一个比m,但是又是在那堆数里面未选择过的最大的数.如此反复,直到最后. 所以,最终做法就是利用回溯法.时间复杂度是O(nlgn)?是这个吗?我也不知道.遇到回溯题目的 时间复杂度总是不太会算. PS:这里利用了类似于位图的方法,避免从大到小排序花费更多的时间. ---------------------------------------------------------------------------------- */ #include<stdio.h> #include<memory.h> int nNums[104] ; //记录相关数字的个数 int FindMinSelect(int m,int nLen,int nMaxNum) ; int main(void) { int i = 0 ; int n = 0 ; int m = 0 ; int t = 0 ; int nMaxNum = 0 ; int nTemp = 0 ; int nLen = 0 ; freopen("in.txt","r",stdin) ; scanf("%d",&t) ; while(t-- > 0) { memset(nNums,0,sizeof(nNums)) ; scanf("%d%d",&m,&n) ; nLen = 0 ; nMaxNum = -1 ; for(i = 0 ; i < n ; ++i) { scanf("%d",&nTemp) ; nNums[nTemp]++ ; if(nTemp > nMaxNum) { nMaxNum = nTemp ; } } printf("%d\n",FindMinSelect(m,nLen,nMaxNum)) ; //nMaxNum为下一个开始搜索的数,也就是最大下标 } return 0 ; } int FindMinSelect(int m,int nLen,int nMaxNum) { int i = 0 ; int nResult = -1 ; if(0 == m) { return nLen ; } else { for(i = nMaxNum ; i >= 1 ; --i) { if(nNums[i] != 0 && m >= i) //i既是索引又是要选择的数 { m -= i ; nNums[i]-- ; nResult = FindMinSelect(m,nLen+1,i) ; m += i ; nNums[i]++ ; if(nResult != -1) { return nResult ; } } } } return nResult ; }