使用暴力遍历,先用C++,因为C++直接提供了排列组合函数std::next_permutation
其思路算法以注释的形式包含在代码中
程序代码:
#include <cstdio>
#include <algorithm>
int main( void )
{
const unsigned num[12] = { 98, 93, 57, 64, 50, 82, 18, 34, 69, 56, 16, 61 };
// 第一个放左边,再从余下的西瓜中挑出5个放左边,使这5个数的和等于 “总数/2 - 第一个瓜”
unsigned sum = 0;
{
for( size_t i=0; i!=12; ++i )
sum += num[i];
if( sum%2 != 0 )
return 1;
sum = sum/2 - num[0];
}
// 遍历下面mask数组的各种排列组合(0代表选中,1代表不选中),从中挑选出符合题目要求的输出
int mask[11] = { 0,0,0,0,0,1,1,1,1,1,1 };
do
{
// 计算累加和
unsigned sum2 = 0;
for( size_t i=0; i!=11; ++i )
if( mask[i] == 0 )
sum2 += num[i+1];
if( sum2 != sum )
continue;
// 输出
printf( "%02d", num[0] );
for( size_t i=0; i!=11; ++i )
if( mask[i] == 0 )
printf( ", %02d", num[i+1] );
printf( "\n" );
} while( std::next_permutation(mask,mask+11) );
return 0;
}
在C语言中,只需要自己写个相似的算法来替代std::next_permutation,代码如下
程序代码:
#include <stdio.h>
#define bit_next(a) (((((((a)-1)|(a))^(1+(((a)-1)|(a))))&(a))/(1+(((a)-1)^(a))))|(1+(((a)-1)|(a))))
int main( void )
{
const unsigned num[12] = { 98, 93, 57, 64, 50, 82, 18, 34, 69, 56, 16, 61 };
// 第一个放左边,再从余下的西瓜中挑出5个放左边,使这5个数的和等于 “总数/2 - 第一个瓜”
unsigned sum = 0;
{
for( size_t i=0; i!=12; ++i )
sum += num[i];
if( sum%2 != 0 )
return 1;
sum = sum/2 - num[0];
}
// 遍历{ 0,0,0,0,0,1,1,1,1,1,1 }的各种排列组合(0代表选中,1代表不选中),从中挑选出符合题目要求的输出
for( unsigned a=0x3F; a!=0x81F; a=bit_next(a) ) // from 00000111111B to 100000011111B
{
// 计算累加和
unsigned sum2 = 0;
for( size_t i=0; i!=11; ++i )
if( (a&(1<<(11-1-i))) == 0 )
sum2 += num[i+1];
if( sum2 != sum )
continue;
// 输出
printf( "%02d", num[0] );
for( size_t i=0; i!=11; ++i )
if( (a&(1<<(11-1-i))) == 0 )
printf( ", %02d", num[i+1] );
printf( "\n" );
}
return 0;
}
输出是
98, 93, 50, 18, 34, 56
98, 50, 82, 34, 69, 16
98, 82, 18, 34, 56, 61