问题描述:
两队参加象棋比赛,两两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的情况是不一样的.