2013-11-01 27 views
1

我有三个整数变量,可以只取值0,12。我想区分我拥有的所有三个数字的组合,排序不计算在内。假设这些变量被称为x,yz。那么x=1, y=0, z=0x=0, y=1, z=0x=0, y=0, z=1在这种情况下都是相同的数字,我将这个组合称为001区分三个int的值

现在有一百种方法可以做到这一点,但我要求一个优雅的解决方案,无论是为了教育目的。

我想过按位由价值的金额转移001

001 << 0 = 1 
001 << 1 = 2 
001 << 2 = 4 

但随后的数002111既能给6

+0

只是为了澄清,你有三个变量要存储0,1或2吗?用户可以输入001/010/100为1,可以输入002/020/200为2? – Steven

+0

我会在正文中予以澄清。 – pfnuesel

+0

'001'和'110'是否一样? – dasblinkenlight

回答

7

的转变想法是好的,但你需要位计数3。因此,尝试通过两次移位的位数:

1 << (2*0) = 1 
1 << (2*1) = 4 
1 << (2*2) = 16 

添加这些所有的3号和第2位将算多少0你哈ve,第二个2位会计算多少1和第三个2位会计算多少个2

编辑虽然结果是6位长,你只需要低4位的唯一标识符(每个号码选项0,1,2 2位) - 因为如果你知道你有多少01有,那么也确定2的数目。的

所以与其做

res = 1<<(2*x); 
res+= 1<<(2*y); 
res+= 1<<(2*z); 

你可以做

res = x*x; 
res+= y*y; 
res+= z*z; 

因为那时

0*0 = 0 // doesn't change result. We don't count 0 
1*1 = 1 // we count the number of 1 in the 2 lower bits 
2*2 = 4 // we count the number of 2 in the 2 higher bits 

因此可以仅通过4位而不是6

1

对于这样小的数字,这将是最简单的只是检查他们的个人,而不是试图将花式,如:

bool hasZero = false; 
bool hasOne = false; 
bool hasTwo = false; 

// given: char* number or char[] number... 

for(int i = 0; i < 3; ++i) 
{ 
    switch (number[i]) 
    { 
     case '0': hasZero = true; break; 
     case '1': hasOne = true; break; 
     case '2': hasTwo = true; break; 
     default: /* error! */ break; 
    } 
} 
1

如果我没有理解你正确的,你有一些数字序列,可以是1,2或3,其排列顺序不重要(只是不同的组合)。

既然如此:

std::vector<int> v{1, 2, 3}; 
std::sort(v.begin(), v.end()); 

这将让所有正确对齐的不同的组合,你可以很容易地写一个循环来测试相等。

或者,您可以使用std::array<int, N>(其中N是可能值的数量 - 在本例中为3)。

std::array<int, 3> a; 

在这里您将设置a[0]等于你有1 S上的号码,a[1]等于“2的数量等

// if your string is 111 
a[0] = 3; 

// if your string is 110 or 011 
a[0] = 2; 

// if your string is 100 or 010 or 001 
a[0] = 1; 

// if your string is 120 
a[0] = 1; 
a[1] = 1; 

// if your string is 123 
a[0] = 1; 
a[1] = 1; 
a[2] = 1; 

如果您正在寻找将其存储在一个单一的32位整数:

unsigned long x = 1; // number of 1's in your string 
unsigned long y = 1; // number of 2's in your string 
unsigned long z = 1; // number of 3's in your string 
unsigned long result = x | y << 8 | z << 16; 

检索每个数,你会做

unsigned long x = result & 0x000000FF; 
unsigned long y = (result >> 8) & 0x000000FF; 
unsigned long z = (result >> 16) & 0x000000FF; 

这与宏在RBG中发生的情况非常相似。

4

当不同可能性的数量很小时,可以使用查找表。

首先,号码的三位数字的所有可能的组合,例如:

Combinations     N  Indexes 
-------------     -  ------ 
000       0  0 
001, 010, 100     1  1, 3, 9 
002, 020, 200     2  2, 6, 18 
011, 101, 110     3  4, 10, 12 
012, 021, 102, 120, 201, 210 4  5, 7, 11, 15, 19, 21 
022, 202, 220     5  8, 20, 24 
111       6  13 
112, 121, 211     7  14, 16, 22 
122, 212, 221     8  17, 23, 25 
222       9  26 

第一列显示相同的组合;第二栏显示组合的编号(我将它们任意分配);第三栏显示每个组合的索引,计算结果为9*<first digit> + 3*<second digit> + <third digit>

接下来,建立一个查找表中的每个这十个组合,用这种表达作为指标:

9*a + 3*b + c 

其中ab,并c是你有三个数字。该表是这样的:

int lookup[] = { 
    0, 1, 2, 1, 3, 4, 2, 4, 5, 1 
, 3, 4, 3, 6, 7, 4, 7, 8, 2, 4 
, 5, 4, 7, 8, 5, 8, 9 
}; 

这是第一个表的改写,在对应于该值在列N索引值。例如,在索引1,39中找到组合号1;组合2在索引2,618等等。

为了获得组合的号码,只需检查

int combNumber = lookup[9*a + 3*b + c]; 
+0

我喜欢你的方法,但不是N = 4和N = 8不可区分组合的情况吗? – Matt

+0

@Matt是的,你是绝对正确的!感谢您指出这一点,我改变了表来解决这个问题。 – dasblinkenlight

1
int n[3]={0,0,0}; 
++n[x]; 
++n[y]; 
++n[z]; 

现在,N排列中,你有值的X,Y,Z的每一个独特的无序组合的唯一有序组合。

例如,两个X = 1,Y = 0,Z = 0和x = 0,Y = 0,Z = 1会给你N = {2,1,0}