ACM水题-数据选取(AC解题报告)

数据选取
Time Limit:1000MS  Memory Limit:32768K

Description:

欢迎进入“挂羊头,卖狗肉”专柜~~下面继续~~
给定1个数m和n个数{a1,a2,...,an},那么请问,最少需要从这n个数中选出多少个,使这些数之和恰好等于m?

Input:

首先一个整数cas,表示接下来由cas个数据每组数据第一行两个整数m,n(1<=m<=100,1<=n<=10) 第二行包含n个整数,表示数组a, 每个整数在[1,10]之间

Output:

如果有满足条件的选法,输出最少需要选出的个数.否则,输出-1 每组输出占一行.

Sample Input:

2
32 10
3 10 5 2 6 6 8 1 9 8
76 7
9 1 10 7 3 4 8

Sample Output:

4
-1

Hint:

第一组数据选取{10,6,8,8} ,第二组数据无解。

Status   Submit

 

 

题目链接: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 ;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值