有这样一个问题:5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
那我们就有了这样一个思路:假设第一位选手名次开始为一,在这位选手为一的情况下假设第二个人为一(名次可以并列),依次假设下去,即五个循环嵌套,最后使用题目条件判断,满足条件的输出结果,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main() {
int a = 1;
int b = 1;
int c = 1;
int d = 1;
int e = 1;
for (; a <= 5; a++){
for (b = 1; b <= 5; b++){
for (c = 1; c <= 5; c++){
for (d = 1; d <= 5; d++){
for (e = 1; e <= 5; e++){
if (((a == 3) + (b == 2)) == 1 && \
((b == 2) + (e == 4)) == 1 && \
((c == 1) + (d == 2)) == 1 && \
((c == 5) + (d == 3)) == 1 && \
((e == 4) + (a == 1)) == 1)
{
printf("final result: a=%d,b=%d,c=%d,d=%d,e=%d\n", \
a, b, c, d, e);
}
}
}
}
}
}
system("pause");
return 0;
}
打印结果如下:
得到的结果是不是大吃一惊,怎么有的结果竟然没有第一名,开始我们思路很好,代码整体也没问题,但我们忽略了这个细节,我们没有排除不正常的名次,正常的名次肯定中间的名次是不能断(简称名次断节),可以并列,甚至可以都是第一名,那么我们就可以用一种十分巧妙的方法来排除这种名次断节的情况,接下来的讲解略有难度,小伙伴认真听。
定义一个整形,使用整形的最低的五个比特位来存五位选手的名次,从右到左比特位为第一名到第五名,比特位上有1就说明对应的那一位有名次, 比如后五位为00101,有第一名,有第三名,没第二名,这显然是不正确的,,就是1之间不能夹着0,比如00011,只有第一名和第二名,名次存在并列,这显然可以,我们只需在原先条件后加点筛选条件就好了,
判断条件如下:
if (((a == 3) + (b == 2)) == 1 && \
((b == 2) + (e == 4)) == 1 && \
((c == 1) + (d == 2)) == 1 && \
((c == 5) + (d == 3)) == 1 && \
((e == 4) + (a == 1)) == 1)
{
int flag = 0;//他的后五位比特位存名次
flag = flag|(1 << (a - 1));
flag = flag|(1 << (b - 1));
flag = flag|(1 << (c - 1));
flag = flag|(1 << (d - 1));
flag = flag|(1 << (e - 1));
while (flag)//比特位存在1,跳出这个循环有两种情况,\
一种是1之间夹着0,一种是比特位全部向右移动完遇到0退出循环
{
if (!(flag & 1))//排除是110等最低位为0的情况,
{
break;
}
flag >>= 1;//最低位不是0就向后移一位再检查最低位是不是0
}
if (flag == 0)//满足flag==0说明比特位正常移动完毕,比如00111,
这是个可以的结果,flag>>1执行三次之后最低位遇到0,跳出 \
while(flag)的循环,到了这里后flag为00000,flag==0,满足条件,\
输出正确结果
{
printf("final result: a=%d,b=%d,c=%d,d=%d,e=%d\n", \
a, b, c, d, e);
}
}
int flag = 0;//这段代码的作用是每次得到一个满足原始\
条件的a b c d e的数字时用1移位,比如得到a=1,b=2,c=1,d=2,e=3,
flag = flag|(1 << (a - 1));//flag二进制为00001
flag = flag|(1 << (b - 1));//flag二进制为00011
flag = flag|(1 << (c - 1));//flag二进制为00011
flag = flag|(1 << (d - 1));//flag二进制为00011
flag = flag|(1 << (e - 1));//flag二进制为00111//这个00111结果是满足条件的,所以最后输出abcde相应的值
完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main() {
int a = 1;
int b = 1;
int c = 1;
int d = 1;
int e = 1;
for (; a <= 5; a++){
for (b = 1; b <= 5; b++){
for (c = 1; c <= 5; c++){
for (d = 1; d <= 5; d++){
for (e = 1; e <= 5; e++){
if (((a == 3) + (b == 2)) == 1 && \
((b == 2) + (e == 4)) == 1 && \
((c == 1) + (d == 2)) == 1 && \
((c == 5) + (d == 3)) == 1 && \
((e == 4) + (a == 1)) == 1)
{
int flag = 0;
flag = flag|(1 << (a - 1));
flag = flag|(1 << (b - 1));
flag = flag|(1 << (c - 1));
flag = flag|(1 << (d - 1));
flag = flag|(1 << (e - 1));
while (flag)//比特位存在1,跳出这个循环有两种情况,\
一种是1之间夹着0,一种是比特位全部向右移动完遇到0退出循环
{
if (!(flag & 1))//
{
break;//排除是110等最低位为0的情况,
}
flag >>= 1;//最低位不是0就向后移一位再检查最低位是不是0
}
if (flag == 0)//满足flag==0说明比特位正常移动完毕,比如00111,\
这是个可以的结果,flag>>1执行三次之后最低位遇到0,跳出 \
while(flag)的循环,到了这里后flag为00000,flag==0,满足条件,\
输出正确结果
{
printf("final result: a=%d,b=%d,c=%d,d=%d,e=%d\n", \
a, b, c, d, e);
}
}
}
}
}
}
}
system("pause");
return 0;
}
正确结果: