C递归_全排列问题 & 异或^的陷阱

问题描述:

两队参加象棋比赛,两两PK
甲队成员:A,B,C,D,E
乙队成员:a,b,c,d,e
现在有甲队成员抽签选择各自的对手
打印并统计所有可能的对阵组合;

问题分析

本题就是一个排列组合的问题,5个萝卜5个坑有多少种方法,坑不动,萝卜动就可以了.
只需要将乙对五个队员做一次全排列,那么每一种排序都是一种对阵表.

处理思路

比如123做全排列
所有组合:123,132,213,231,312,321
n个数全排列,可以得到的序列一定是n!
怎么得到的?
假设原始序列是一个数组a[n]
从下标为0开始,依次往后取元素,并且与最后一个位置的元素交换,这样只要数组中没有重复的元素,交换过后就一定能产生新的序列,
产生的新的序列就从下标为1开始,依次往后去元素并与末尾元素交换,
就又可以产生新的序列;

依次类推
当我们的遍历的起点跟末尾元素重合时,就不可能再产生新的序列了,因为唯一一次交换时自己跟自己,所以此时我们直接打印出产生的序列就可了.

第一轮从第一个元素开始前进,并与末尾元素进行交换
    123 --> {312 (13交换)  132 (23交换) 123 (33交换))}


    第二轮从第二个元素开始前进,并与末尾元素进行交换
        312  --->{321(12交换)   312(22交换)}
        132  --->{123(32交换)   132(22交换)}
        123  --->{132(23交换)   123(33交换)}
            第三次从第三个元素开始与数组中元素精灵遍历,发现都是跟自己做交换所以直接打印结果
            321  312  123  132  132  123
# define _CRT_SECURE_NO_WARNINGS
# include<cstdio>
# include<cstdlib>

#define TOTAL 5

int count = 1;
void print(char a[])
{
    int i;
    for (i = 0; i < TOTAL; i++)
    {
        printf("\t\t\t\t%c --VS-- %c\n", 'A' + i, a[i]);
    }
}

void Swap(char a[],int m, int n)
{
    char temp;
    temp = a[m];
    a[m] = a[n];
    a[n] = temp;
    /*a[m] = a[m] ^ a[n];
    a[n] = a[m] ^ a[n];
    a[m] = a[m] ^ a[n];*/
}


//k表示当前选取到第几个数,m表示共有多少数.  
void AllRange(char  a[], int k, int m)
{
    int i;
    if (k == m)
    {
        static int s_i = 1;
        printf("\t\t\t第%d种对阵列表:  \n", count++);
        print(a);
        putchar('\n');
    }
    else
    {
        for (i = k; i <= m; i++) //第i个数分别与它后面的数字交换就能得到新的排列  
        {
            Swap(a,k, i);
            AllRange(a, k + 1, m);
            Swap(a,k, i);
        }
    }
}

int main()
{
    srand((unsigned)time(NULL));
    char a[TOTAL],i;
    for (i = 0; i < TOTAL; i++)
    {
        a[i] = i + 'a';
    }
    puts("\t\t\t所有抽签组合如下:\n\n");
    AllRange(a, 0, TOTAL-1);
    getchar();
    return 0;
}

这里写图片描述
这里写图片描述

异或^使用的陷阱

上面的全排列问题,在处理的过程当中,我们不难发现.当遍历数组元素与末尾元素交换过程的起点 != 末尾元素位置时,每一轮都会有一次自己与自己交换,如果此时使用^进行两个变量值的交换就会讲该元素的值变为0,比如:
int a =10;
a = a^a;
此时a = 0;
注意:这和int a = 10,b =10;然后用异或交换ab的情况是不一样的.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值