算法(44)-动态规划(3)-背包-最小不可组成和-C++

最小不可组成和:两种情况:
1.[min,max] 如果有一个数不能被某个子集得到,求:最小的那个数
   arr[3,2,5]  sum={2,3,5,5,7,8,10}  少{4,6,9} 返回4
 2.[min,max] 如果都有,那么max+1是arr最小不可组成和
 arr[1,2,4]  sum={1,2,3,4,5,,6,7}  返回8
解法:暴力递归: 略
           动态规划:背包bool二维表
           1.行arr ;列 sum+1; dp[i][j]: arr[0..i]自由选择能否累加出j来
            2.三种情况
              2.1.位置对应的数肯定为true
              2.2. 第二行开始,只选前一个数 dp[i-1][j]
              2.3. 当前数和前一个数 dp[i-1][j-arr[i]]
 

int unformedSum(vci arr)
{
	int sum = 0;
	int m_min = RAND_MAX;//
	for (int i = 0; i != arr.size(); i++)//提前要求sum  和最小值
	{
		sum += arr[i];
		m_min = min(m_min, arr[i]);
	}
	cout << "m_min=" << m_min << endl;
	cout << "sum" << sum << endl;
	int N = arr.size();
	int row = arr.size();//3;//行
	int col = sum+1;//10;//列
	vector<vector<bool> > vcidp(N); //这个N一定不能少
	for (int i = 0; i < row; i++)
	{
		vcidp[i].resize(col);
	}
	vcidp[0][arr[0]] = true; //第0行全是true  第0列 全是false
	for (int i = 1; i < N; i++)     //填二维表
	{
		for (int j = 1; j <= sum; j++)
		{
			if (arr[i] == j)                      //背包问题三个条件 1.本身
			{
				vcidp[i][j] = true;
			}
			else if (vcidp[i - 1][j])                             //2.上面的位置
			{
				vcidp[i][j] = true;
			}
			else if (j - arr[i] >= 0 && vcidp[i - 1][j - arr[i]])3.上面位置的偏移量 前面的条件表示不越界,后面是偏移量
			{
				vcidp[i][j] = true;
			}
		}
	}
	
	//最后一行的值选最小
	//int ans = m_min;
	for (int ans=m_min; ans <= sum; ans++)
	{
		if (!vcidp[N-1][ans])    //最后一行 最小的不能组成的,就是数组中是false 的返回
		{
			return ans;//第一种情况,最小的一个
		}
	}
	return sum + 1;// 第二种情况 max+1
}
void smallestUnFormedSum_main()
{
	    cout << "****smallestUnFormedSummain*********" << endl;
		vci vci1;
		vci1.insert(vci1.begin(), { 3, 2, 5 });
		cout << "arr[3, 2, 5] 返回4---" << unformedSum4(vci1)<< endl;
		vci vci2;
		vci2.insert(vci2.begin(), { 1, 2, 4 });
		cout << "arr[1, 2, 4] 返回8---" << unformedSum4(vci2) << endl;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值