首页
社区
课程
招聘
[旧帖] [推荐][推荐]给大家推荐一个很有趣的算法问题! 0.00雪花
发表于: 2010-4-16 21:02 1540

[旧帖] [推荐][推荐]给大家推荐一个很有趣的算法问题! 0.00雪花

2010-4-16 21:02
1540
今天无意之中在一个VC的教程上看到了一个很有趣的算法问题的求解,与大字分享一下算法带来的乐趣!!!!!!                  
猫吃老鼠问题的求解
一、问题描述
    现有n个老鼠围成一圆圈,有一只猫从任意位置开始吃老鼠,每次都隔一个老鼠吃,请给出最后一个老鼠的编号?题目要求是任给老鼠数n,输出猫最后吃的老鼠的编号。
二、问题求解
我们假设老鼠按顺时针方向编号,猫从第一号老鼠开始吃。比如现有4个老鼠围成一个圆,则猫吃老鼠的顺序应该为1->3->2->4,即最后一个吃的老鼠的编号是4。
   程序设计思路说明:
   猫从老鼠数组从头开始移动,如果碰到老鼠且间隔标志为1,则吃该老鼠,然后间隔标志置为0,剩下的老鼠数减1,继续向后移动;如果碰到老鼠但间隔标志为0,则不吃该老鼠,间隔标志置为1,然后向后移动;如果没有碰到老鼠则继续向后移动;如果移动到数组末则再从头开始以实现圆循环。
   老鼠数组ipArray用来表明特定位置是否有老鼠存在,1表示有老鼠存在,0表示此处的老鼠已被吃掉。
   间隔标志ijian为1,表示接下来如果碰到老鼠就可以吃掉;如果为0,则表示刚吃过老鼠应该隔一个再吃,这时碰到下一个老鼠就置间隔标志为1,但并不吃老鼠。
   剩下的老鼠数iyu在每吃掉一个老鼠后进行减一操作;当剩余老鼠数为1时,则直接找出该老鼠位置,并输出其编号,也就是数组下标值加1,到此程序结束。

#include <iostream.h>
int main(int argc, char* argv[])
{
    cout<<"请输入老鼠数:";
    int itotal;        //老鼠总数
    cin>>itotal;
    int iyu=itotal;   //剩下未吃的老鼠数
    int ipoint=0;  //移动指针   //指示猫的当前位置
        int ijian=1;   //间隔标志  //1表示已经间隔了一个老鼠,0表示未间隔
        int * ipArray;  //数组指针
       
        if(iyu<1)
        {
                cout<<"老鼠数不能小于1!"<<endl;
                return 0;
        }
        if(iyu==1)   //如果只有一只老鼠,则直接输出返回
        {
                cout<<"  "<<ipoint+1<<endl;
                cout<<"结束!"<<endl;
                return 0;
        }
       
        cout<<"共"<<itotal<<"个老鼠!"<<endl;
                cout<<"以下是吃老鼠的顺序输出:"<<endl;

        ipArray=new int[iyu];  //生成数组
        for(int i=0;i<iyu;i++)    //初始全部位置都有老鼠存在
        {
                ipArray[i]=1;           //1表示该位置存在老鼠
        }
       
       
        for(;;)  //循环开始,依次隔一个吃老鼠,直到只剩下最后一只老鼠,输出并程序结束
        {
                ipoint=ipoint%itotal;  //确保在数组范围内
                if(iyu==1)   //只剩最后一只的老鼠,直接找出即可
                {
                        if((ipArray[ipoint]==1))   //碰到老鼠
                        {
                                cout<<"  "<<(ipoint+1)<<endl;
                                cout<<"结束!"<<endl;
                                return 0;       
                        }
                }
                else
                {
                        if((ipArray[ipoint]==1))   //碰到老鼠
                        {
                                if(ijian==1)  //如果已跳过一个老鼠,则现在就可以吃
                                {
                                        cout<<"  "<<(ipoint+1)<<endl;   //输出吃掉的老鼠号
                                        ipArray[ipoint]=0;  //条件满足则吃老鼠,置该位为0;
                                        ijian=0;             //置间隔标志为0;
                                        iyu--;              //剩下要吃的老鼠数减一
                                }
                                else     //如果刚吃过一个老鼠
                                {
                                        ijian=1;    //设置间隔标志为1
                                }
                        }
                }
                ipoint++;    //移动猫的位置
        }//endfor
        return 0;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错   加油啊
2010-4-16 22:12
0
雪    币: 224
活跃值: (55)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
3
嗯,LZ给出的方法很简洁...
看了题目后我也试着去实现了下,下面是我的思考,发来交流下了。
我每次把还剩的老鼠都排成一排,用数组arr表示,这样猫可从arr[0]或arr[1]开吃。主要是确定它从那个开吃,这由1.前一次吃时是从arr[0]还是arr[1]开始;2.前一次吃时剩的老鼠总数是奇还是偶这两个因素决定。程序中用bool值b来记录,b真则从arr[0]开吃。
第一次猫从arr[0]起吃了,即吃的老鼠编号为1、3、5...这样现在arr中的老鼠的编号为2、4、6...同时这里要算出b值,然后进行下一次while循环。
若现有老鼠偶数只,如这次从arr[0]起吃(b=1),则现在的最后一只不会被吃,下次应从arr[0]起吃(b=1);如这次从arr[1]起吃(b=0),则下次会从arr[1]起吃(b=0)。当前老鼠数为奇的情况分析类似。
#include <stdio.h>

void main(){
	int num=0;
	bool verbose=0;
	int* arr=0;
	int i=0;
begin:printf("numeber of the mouse?\n");
	scanf("%d",&num);
	printf("output the eat sequence (bool value)?\n");
	scanf("%d",&verbose);

	arr=new int[num*sizeof(int)];
	for(i=0;i<num;i++)
		arr[i]=i+1;
	bool b=1;		//1表示从arr[0]开始吃,0表示从arr[1]开始吃
	int n=num;				//n表示还剩的老鼠数
	while(n>1){
		if(n%2==0){
			for(i=0;i<n/2;i++){
				if(verbose)
					printf("%d,",b?arr[2*i]:arr[2*i+1]);	//这次被吃的老鼠
				arr[i]=(b?arr[2*i+1]:arr[2*i]);	//这次吃剩的老鼠再排
			}
			printf("\n");
			b=(b?1:0);		//n为偶,若从arr[0]起吃,则最后一只不被吃,下次从arr[0]起吃...
			n/=2;
		}
		else{
			for(i=0;i<n/2;i++){
				if(verbose)
					printf("%d,",b?arr[2*i]:arr[2*i+1]);
				arr[i]=(b?arr[2*i+1]:arr[2*i]);
			}
			n/=2;
			if(b){			//从arr[0]起吃,最后一只被吃
				if(verbose)
					printf("%d,",arr[2*i]);
			}
			else{			//从arr[1]起吃,最后一只不被吃
				arr[i]=arr[2*i];
				n+=1;
			}
			printf("\n");
			b=(b?0:1);
		}
	}	
	printf("the last live mouse's numeber is %d.\n",arr[0]);
	delete[] arr;

	char c='n';
	printf("another group of unfortunate mice?\n");
	scanf(" %c",&c);
	if(c=='y' || c=='Y')
		goto begin;
}
2010-4-17 14:41
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
4
不错,不错!!
2010-4-17 16:15
0
雪    币: 37
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
挺不错的哟!考编程功底的时候到了
2010-4-17 20:38
0
雪    币: 62
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习了!!!
2010-4-18 13:01
0
雪    币: 79
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
//若从1号算起
  int total = 1;
  printf("老鼠个数?\n");
  scanf("%d",&total);
  int seed = 1;
  while(seed < total) seed<<=1;
  printf("最后一个吃掉的是:%d\n",2*total-seed);

若从任意号算起,只要在此基础上加入一个计算偏移量的代码即可。
2010-4-18 15:02
0
游客
登录 | 注册 方可回帖
返回
//