C语言求解欧拉错位排列

【题目】就是有标号1到6的六只瓶子。和1到6的盖子。把瓶盖安在瓶子上      求瓶子和瓶盖数字没有任何相同的情况

善良的黑藻同学找到这个问题   我发现自己高中的数学已经完全忘光了。。。排列组合么?觉得没法算了,没办法回归本行    让电脑帮我算。。。

最开始用了一个穷举的算法   用了6层for循环    把结果求了出来    265   但是 这真的很汗     这种方法笨的可以      绝不是正道      其实这题的本质是一个叫欧拉错位排列的题    意思和上面的题目差不多    可以把它理解为   1——N个瓶子和1——N个瓶盖的错位匹配问题   

这样一个问题用穷举是不可能得出每一个情况的答案的     必须换一个方法     我想到了回溯法    就是试探性的瓶子上放进瓶盖     不符合条件就换一个瓶盖    当无法进展下去的时候    倒退一步求解        这也是N皇后问题    以及四色问题的求解思路

于是我开始着手这样写       果然OK了     多说无益   详见源码

#include <conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int judge(int *a,int i,int j,int n)      //判断瓶盖放在某瓶子上是否满足条件   满足则返回0   不满足返回1
{
if(j>n||i>n)
{
   return 1;
}
if(a[i]==i)
{
   return 1;
}
int k;
for(k=1;k<i;k++)
{
   if(a[k]==j)
   {
    return 1;
   }
}
return 0;
}

void out(int *a,int n)                 //输出函数
{
int i=0;

FILE *h=fopen("答案.txt","a");
for(i=1;i<=n;i++)
{
   fprintf(h,"%d",a[i]);
   fprintf(h,"%c",' ');
   printf("%d",a[i]);
   printf(" ");
}
fprintf(h,"%c",'/n');
printf("/n");
fclose(h);
}

int make(int *a,int n)                      //用回溯法计算的过程
{
FILE *h=fopen("答案.txt","a");
if(n<=1)
{
   fprintf(h,"%d",0);
   return 0;
}
memset(a,0,256);
int j=1,i=1,num=0;
   while(1)
   {
    if(a[1]>n)
    {

     break;
    }
    if(j>n)
    {
     i--;
     j=a[i]+1;
    }
    a[i]=j;
   
    if(judge(a,i,j,n))
    {
     j++;
    }
    else
    {
     j=1;
     i++;
    }
    if(i>n)
    {
     i=n;
     j=a[i];
     j++;
     out(a,n);
     num++;
    }

   }
  
   return num;
}

int main()
{
int n=0;
int a[256]={0};
FILE *h=fopen("答案.txt","w");

fprintf(h,"%s","感谢绵羊同学使用");
fprintf(h,"%c",'/n');
fprintf(h,"%c",'/n');
fclose(h);
while(1)
{
  
   puts("【题目】有标号1到N的N只瓶子。和1到N的盖子。它们没有任何数字相同的配对方式总共有多少?/n/n");
   printf("请输入N的值(N的数值不要过大 否则算的会很慢——!):/n");
   scanf("%d",&n);
   FILE *h1=fopen("答案.txt","a");
   if(n!=1)
   {
    fprintf(h1,"以上是当N等于%d时的答案",n);
    fprintf(h1,"%c",'/n');
   }
   int num=make(a,n);

   printf("符合要求的排列有:%d个/n/n",num);
   printf("如果想换个N运算 摁回车继续.../n");
   while(getchar()!='/n');
   getch();
   system("cls");
   fclose(h1);
}

 

return 0;
}

写程序就是这样   遇到身边的疑难尝试着去解决   解决的多了    也就成长了   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值