没讲明白的水题orz

有一道解释程序的水题没给非计算机专业的同学讲明白orz,在这里再练一下。。

源代码完全没有缩进真是难以忍受。。

p.s.懂递归就不用看了#include <stdio.h>

int n = 0;
int rest[7][7];
void swap(int *a, int *b) {   int m;   m = *a;   *a = *b;   *b = m; }
void perm(int list[], int k, int m) {   int i;   int j;
  if(k > m)   {   for (i=0; i<7; i++)//判断list是否可行,不行就返回,行就输出list   {   for (j=0; j<7; j++)   {   if (rest[i][j] == 0)   return;   if (rest[i][j] != list[i])//list存结果   continue;   if (rest[i][j] == list[i])   break;   }   }
  n++; printf("Solution: %d\n", n); printf("赵 钱 孙 李 周 吴 陈\n"); printf("=============================================================\n"); for(i = 0; i <= m; i++) { switch (list[i]) { case 1: printf("星期一 "); break; case 2: printf("星期二 "); break; case 3: printf("星期三 "); break; case 4: printf("星期四 "); break; case 5: printf("星期五 "); break; case 6: printf("星期六 "); break; case 7: printf("星期日 "); break; default: break; } } printf("\n\n\n"); } else { for(i = k; i <= m; i++)//实验所有可能的list的组合,7!次 { swap(&list[k], &list[i]); perm(list, k + 1, m); swap(&list[k], &list[i]); } } } int main() { printf("\n"); printf("注意:\n"); printf(" 1.请按钱、赵、孙、李、周、吴、陈的顺序输入休息每个人的时间。\n"); printf(" 2.输入星期时,请直接输入数字,如要输入'星期一',就用'1'代替,以此类推。\n"); printf(" 3.星期与星期之间用空格隔开,每输入完一个人的休息日,在其后输入0,再按回车继续下一人。\n"); printf("\n"); int list[] = {1, 2, 3, 4, 5, 6, 7}; int i, j; for(i = 0; i < 7; i++) { printf("请输入第 %d 个人的休息时间:\n", i+1); for(j = 0; j < 7; j++) { scanf("%d", &rest[i][j]); if(rest[i][j] == 0) break; } } printf("\n\n\n"); perm(list, 0, 6); getchar(); getchar(); printf("输出完毕,按回车键结束!\n"); return 0; }

  0.看见swap用来交换

  1.这么一坨代码首先看main,了解到输入的rest数组是每个人的希望的休息时间。

  2.看见用rest【i】[j]与list[i]进行比较,下文将list转换成星期几输出,那么list应该是保存的结果。

     两个for循环是判断list是否可行。对于list[x],查找对应的第x人的愿望单里有没有这个数字,有就找下一个人,全通过了意味着方案可行,下面用来输出list;没有就返回上一层函数;

  3.重点是这里,用了递归 

       for(i = k; i <= m; i++)

      {
      swap(&list[k], &list[i]);
      perm(list, k + 1, m);
      swap(&list[k], &list[i]);
     } 
程序的主要思路为尝试从1到7的数字的所有组合,如果符合条件,就输出。这样一共要进行7!次测试。
那么如何进行从一到七的全排列呢?
先看一下我们怎么全排列 1 2 3。一共可以排列的方式如下:
 1 2 3
 1 3 2
 2 1 3
 2 3 1
3
1 2
 3 2 1
 我们让不同的数字分别打头,然后交换剩下的数字。
 更近一步:如何进行1到4的全排列呢?
 同样的,我们让不同的数字打头。
 1 int[3](开头数字1,后面是一个长度为3的数组)
 ......
 2 int[3]
 ......
 ......
 4 int[3]
  我们把打头数字相同的看做一组数字,这样一共有4组数字。
 对于每组数字,我们需要将他们尾部的数组全排列,也就是重复四次上面排列1 2 3的方法,注意每次操作对象不同。一共操作4*(3*2)次
 从 1到5也是同理,我们将他们分为5组。
  1 [4]
  2 [4]
  .....
  5 [4]
  对于每组数,我们将它尾部的数组用上面排列4个元素的方法进行排列,而排列4个元素的方法又要用到排列3个元素的方法,排列3个元素又要用到排列2个元素的方法。
  于是总排列次数为5*4*3*2*1=120次
我们看到,每次排列都要用到比自己更小的数的排列方法,排列x个数方案为x!。

 现在我们回来看代码。
 排列1到7,我们需要排列7!次。首先要把1到7分成七组,让每个数字轮流打头。
 所以for(0,<6,++)。(在末尾的时候你必须要把元素换回来,要不换下一个数时数组就乱了。所以结尾也要swap();)
   {swap();
    ...}
 在这7次循环中,每次你都要用到排列后面6个数的方法,用到6次自己,只需要调用自己,把参数改成6就行了,所以 

      for(i = k; i <= m; i++) //k==0

      {
      swap(&list[k], &list[i]);
      perm(list, k + 1, m);
      swap(&list[k], &list[i]);
     } 
而排列6个数就要用到排列5个数的方法,这样一直下去函数一共嵌套了7层,第1层执行7遍,第2层执行6遍,以此类推,一共执行7!遍.
——————————————————————————
emmmmmmmm还没懂我就再改改
  

   

猜你喜欢

转载自www.cnblogs.com/pornhub/p/9216153.html