for(i = 0; i < (1 << type); i++){ //位运算实现所有情况的枚举
for(j = 0; j < type; j++){ //依次与每一位是否选取进行比较
if(i & (1 << j)){ //如果该情况与某一位对应成功
sumv = sumv + obj[j].v; //价值相加
ispace = ispace + obj[j].w; //体积相加
}
}
if(sumv > sumvfinal && ispace <= space){ //判定,总价值是否大于上次循环的总价值,体积是否过大
sumvfinal = sumv; //总是将最大的价值赋给sumvfinal
choice = i; //将该种情况取得物体情况赋给choice
left = space - ispace; //算出剩余空间
}
ispace = 0; //让总体积总价值还原为0,以便再次循环
sumv = 0;
}
for(i = 0; i < type; i++){ //将choice转换为二进制,确定选了哪几个物体
if(choice & (1 << i)){
names[i] = i + 1; //如果选择了某个物体,则保存该物体的编号到names[i]
}
else{
names[i] = 0; //否则赋值为0,便于输出时判断
}
1.枚举法:
主要思想是利用二进制0,1判断真假/是否放入,其中涉及到二进制数枚举,位运算&以及移位操作,左移<<。
(1)type是物体的种类,1<<type的意思是:将1转换成二进制数,并把1向左移动type位,这实际上是实现了type个2相乘,也就是2^type,然后根据0,1来判断真假的时候,正好有这么些种情况。这样就通过位运算实现了全部情况的枚举。
(2)既然type是物体的种类,那么对于int j<type来说,如果用1来表示是否取得,每一个1<<j其实都表示了第几个种类的物品被取得了,也就是1。
(3)那么,对于每一种情况i,都让他去和所有的1<<j去比对,也就是每种情况下取得的物品情况去和每一个位置的物品去比对,看是否取得,那就用i & (1<<j)去验证,如果不为0,也就是真,那就执行一系列赋值操作,如果为0,也就是没取得,那就进行下一种情况的比对。
(4)&运算:对于&两侧的数字,将其化为二进制数再进行比对,结果也是二进制数,只不过在最后的时候转换为了十进制数。
如果相同位置的数都为1,则结果的对应位置的数也为1,否则结果对应位置的数为0。
比如,对于5&6,那运算中是0000 0101 & 0000 0110 = 0000 0100 = 4。