回 帖 发 新 帖 刷新版面

主题:第46次编程比赛第二题(趣味题)

一座山上周围有n个洞,顺时针编号为0,1,2,……,n-1。
而一只狼从0号洞开始,顺时针方向计数,每遇到m个洞就进洞找兔子,
例如n=5 m=3 狼经过的洞依次为0,3,1,4,2,0
输入n、m。试问兔子有没有幸免的机会?

编写一个完整的程序  n m 由scanf输入

有幸免的机会输出Y
没有输出N

回复列表 (共19个回复)

沙发

- - (n,m)=1,即n,m互质,兔子必死。
计算(n,m)用简单的Euclid算法即可。

code就不写了,给其他朋友拿头奖的机会

板凳

这道题估计很多人都能猜出来,当m与n互素时答案就必定是‘N’,若是非互素的话答案就是‘Y’了。最主要是证明。这里我用抽象代数里面的群论来证明。
整数(0~n-1)和模n加法组成一个循环群Zn,当群元素m(0<=m<=n-1),能够通过反复多次的模n自加(即(m+m+...+m)mod n)生成群中所有元素,则m称为循环群Zn的生成元。而一个元素是该循环群的生成元的充要条件就是GCD(n,m)=1,证明如下:

元素m是群Zn的生成元<=>
由于数字'1'属于该群中,必定存在一个数整k,使得(k*m)mod n=1
<=>存在整数p,使得k*m+p*n=1
<=>根据数论中的最大公因子定理,则GCD(m,n)=1

因此用辗转相除法判断m,n是否互素,如果互素,则表示0~n-1的任何整数都能由m模n自加多次得到,因此兔子无路可逃。
而且,即使是n<m,其结果也和n,(m mod n)的结果相同,即n=5;m=7的结果与n=5;m=2的结果相同。

程序如下:


    int GCD(int x,int y){
        int temp,r;
        if(x<y) {temp=y;y=x;x=temp;}        
        for(r=x%y;r;r=x%y) 
        { 
            x=y;y=r; 
        } 
        return y;
    }

int main(int argc, char* argv[])
{
   int res=0;int gcd=1;
   int m,n;
   scanf("%d,%d",&n,&m);
   if((n<1)||(m<0)){
       printf("Invalid Input");
       return 0;
   }
   else{
       if(n==1)res=0;//只有一个洞,兔子无处藏身
       else{
        if(m==0)res=1;//m=0表示狼不前进,兔子可在除0好洞外其余地方藏身
        else {
            gcd=GCD(n,m);
            if(gcd==1) res=0;
            else res=1;
        }
       }
   }
   printf("%c\n",res?'Y':'N');
   return 0;
}

3 楼

只想到暴力算法,O(n)的,不知道有什么数学方法可以在O(1)内算出来。

4 楼

#include <stdio.h>

int main(void)
{
    int n,j,k=0,flag=0,m,*p,*head,i;
    scanf("%d %d",&n,&m);
    p=(int*)malloc(sizeof(int)*n);
    for(i=0;i<n;i++)
       p[i]=0;
    *p=1;
    j=m;
    while(j!=0){
       p[j]=1;
       j=(j+m)%n;
      }
    for(i=0;i<n;i++){
        if(p[i]==0){
        flag=1;
        break;
      }
    }
    if(flag==1)
      printf("%c",'Y');
    else
      printf("%c",'N');
    return 0;
}

5 楼

#include"stdio.h"
main()
{int m,n,i,j,k,t,x,s[10000][2];
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
{s[i][1]=i;
s[i][0]=0;}
x=0;
for(i=0;i<10000;i++)
{
j=i%m;
if(j==0)
{k=i%n;
for(t=0;t<n;t++)
if(s[t][1]==k)
s[t][0]=1;
}}
for(i=0;i<n;i++)
if(s[i][0]==0)
x++;
if(x!=0)
printf("Y\n");
else
printf("N\n");
}

6 楼

#include "stdio.h"

int main(int argc, char* argv[])
{
    int m,n;
    int num = 0;
    printf("Input n and m:\n");
    if(!scanf("%d,%d",&n,&m))
        printf("ERROR!");
    int *a = new int[n];
    
    for(int i = 0;i < n;i ++)
        a[i] = 1;    
    for(i = m - 1;n - num > 0;i += m)
    {
        for(;i >= n;)
            i = i - n;
        if(a[i] != -1)
        {
            a[i] = -1;
            num ++;
            if(num == n)
                printf("兔子不能幸免.狼最后进入的洞是%d.\n",i%n);
        }
        else
            break;
    }
    if(num != n)
    {
        printf("兔子幸免的机会为: %d/%d\n可以幸免的洞有:\n",n-num,n);
        for(i = 0;i < n;i ++)
        {
            if(a[i] != -1)
                printf("%d,",i);
        }
        printf("\n");
    }

    delete []a;
    return 0;
}

7 楼


#include<iostream>
using namespace std;
/*
因为题目没给出n的范围,所以我只设了长度为1001
只能测n<=1000的情况 具体情况请题主自由设定tag长度
*/
int deal(int m,int n,int tag[])
{
    int drift(m);
    int count(1);
    while(drift!=0)
    {
        if(drift>=n)
            drift=drift%n;
        if(0==tag[drift])
        {
            count++;
            tag[drift]=1;
        }
        drift+=m;
        if(drift>=n)
            drift=drift%n;
    }
    if(count==n)
        return 0;
    else return 1;
}

main()
{
    int m,n;
    cout<<"请输入m"<<endl;
    cin>>m;
    cout<<"请输入n"<<endl;
    cin>>n;
    int tag[1001];
    memset(tag,0,sizeof(tag));
    if(deal(m,n,tag))
        cout<<"Y"<<endl;
    else cout<<"N"<<endl;
}

8 楼

#include<iostream>

using namespace std;

int main()
{
    int n,m,sum=0,i,j;

    cin>>n>>m;

    int *p=new(int[n]);

    for (i=0;i<n;i++)p[i]=1;

    j=i=0;

    while (sum!=n)
    {
        if (i%m==0)
            if (p[j])
            {
                p[j]=0;
                sum++;
            }
            else break;
        i++;
        j=i%n;
    }

    cout<<((sum==n)?'N':'Y');
    delete[] p;
}

9 楼

#include<iostream>

using  std::cout;
using  std::cin;
using  std::endl;

unsigned long gcd(unsigned long a, unsigned long b) 

    
   if(a<b)
    { 
      unsigned long  d;    
      d = b; 
      b = a; 
      a = d; 
     } 
   unsigned  long c=0; 
   while(c = a % b)
      {a = b; 
       b = c; 
     } 
return b; 
}

 
int main()
  {   cout<<"Please Press 0  to Exit"<<endl;
      
  for(unsigned  long ula=0;cout<<"The N is: ";
        cout<<"Please Press 0  to Exit"<<endl)
     {
       cin>>ula;
      if(!ula) {cout<<"N not ex to no ul int!!!";
                  exit(-1);}
      
      cout<<"The M is: ";
      unsigned  long ulb=0;
      cin>>ulb;
      if(!ulb) cout<<"M not ex to  no ul int!!!";
      
      if(gcd(ula,ulb)==1)
      cout<<"N"<<endl;
      else cout<<"Y"<<endl;
      }
     
     return(0); 
}
***********************************************************************
   在做这个过程中 我发现了一个问题,  我的电脑是 winxpsp2  +  Dev C++4.9.9.2
 为了 看看 整形的具体情况 我做了一个测试  发现以下奇怪问题,希望有人帮我解答下:::::
  long long int 的sizeof 值为8  可是实际我弄了下 发现实际取值如下:
                    (-2的31次方+1)到(+2的31次方-1)
unsigned long long sizeof值也是8   实际却取值 如下:
                            0  到(+2的31次方-1)
               而不是理论的  0到 (+2的32次方-1)
 long  int  的sizeof 值是4  可是实际取值同long long int 一样;
unsigned long int  的sizeof  值也是4 可实际取值也和unsigned long long 一样;
  ***************************
相当疑惑中************************************

10 楼

#include <stdio.h> 
#include <stdlib.h>
#include <malloc.h>
#include <cstdio>
#include <cstring>
#include <ctime>

void Init(int num[], int n);
void Search(int num[], int n, int m);
void Judge(int k, int n);

int main(void)
{
    int n, m; 
    int *num;  

    clock_t start, end;
    start = clock();

    printf("请输入洞的数量和隔几个洞找n和m : ");
    scanf("%d%d", &n, &m);
    num = (int *)malloc(n * sizeof(int));


    Init(num, n);
    Search(num, n, m);

    end = clock();
    printf("时间:%f秒\n", (end-start)/(double)CLK_TCK);

    free(num);
    return 0;
}
void Init(int num[], int n)
{
    int i;
    for(i = 0; i < n; i++)
    { 
        num[i] = i;
    }
}
void Search(int num[], int n, int m)
{
    int count, k, l, i;
    int *s;
    
    s = (int *)malloc(n * sizeof(int));

    count = 0;
    k = 0;
    l = 0;
    for(i = 0; l < n; i++)  
    { 
        if(i == 0)
        {
            ;
        }
        else
        {                 
            count++;
            if(count % m == 0)
            {
                s[k++] = num[i % n];
//                printf("%4d", num[i % n]);
                if(i >= n && num[i % n] == 0)
                    break;
                else
                    l++;
            }
        }
    }
     Judge(k, n);
}
void Judge(int k, int n)
{
    if(k < n)
    {
        printf("\nY\n");
    }
    else
    {
        printf("\nN\n");
    }
   
}
     





我来回复

您尚未登录,请登录后再回复。点此登录或注册