有意思的逻辑思维题(三)(hdu2211,蓝桥杯蚂蚁感冒)

杀人游戏

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2211

题目描述:

现在已知有N个土匪站在一排,每个土匪都有一个编号,从1到N,每次杀人时给定一个K值,从还活着的土匪中,编号从小到大的找到K个人,然后杀掉,继续往下,直到找遍,然后继续从剩下的土匪中,编号从小到大找到第K个活着的土匪,然后杀掉。比如,现在有10个土匪,K为3,第一次杀掉3,6,9号的土匪,第二次杀掉4,8号土匪,第三次杀掉5号土匪,第四次杀掉7号土匪,第五次杀掉10号土匪,我们看到10号土匪是最后一个被杀掉的(从1到K-1的土匪运气好,不会被杀!)。现在给定你一个N和一个K,问你最后一个被杀掉的土匪的编号是多少。




解题思路:

其实这是一道比较典型的约瑟夫环的问题

http://baike.baidu.com/link?url=RnHDh0kg0uEeh-H_a4ZRMI1d3pZ1qbJYpwLdcY3VvZ8LwLxsVNmGODmIilRKhgBnmI3phVO_lLOavxcQgALT1_


约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后[1]  结果+1即为原问题的解。

约瑟夫环运作如下:
1、一群人围在一起坐成[2]  环状(如:N)
2、从某个编号开始报数(如:K)
3、数到某个数(如:M)的时候,此人出列,下一个人重新报数
4、一直循环,直到所有人出列[3]  ,约瑟夫环结束


不过当年萌新的我是不知道这么个东西的 ,但是差不多想明白了其规律性,假设m个土匪,那么第一轮死亡的人编号为k的倍数,第二轮死亡的依次是k+1,2K+2,3K+3……

(m-1)/(k-1)为该周期m前面死亡的人数,即m之前所对应的差值

#include<stdio.h>
int kill(int n,int k)    //杀人游戏 
{
    if(n==k)            //如相等,则最后一个人死亡 
	return k;            
    int m;               
    m=kill(n-n/k,k);    //杀人游戏递归 m为最后编号 
    //printf("%d\n",m);
    return (m-1)/(k-1)+m;   //找到m后还原上轮m编号 
	/*m-1为当前轮m前面的人,因为上轮已经死人了,所以是k-1 
  (m-1)/(k-1)为该周期m前面死亡的人数,即m之前所对应的差值*/
}
int main()
{
    int t,x;
    int n,k;           //n为剩余人数,k为周期数 
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        x=kill(n,k);
        printf("%d\n",x);
    }
    return 0;
}


正所谓“这道题我不会,但是AC还是没问题的~”










蚂蚁感冒

某年蓝桥杯省赛题目http://lx.lanqiao.cn/problem.page?gpid=T119

题目描述:长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。 这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。 请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
【数据格式】
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。
接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。
要求输出1个整数,表示最后感冒蚂蚁的数目。


很遗憾当年比赛时没有做出这道题,直到后来听到了一句话才恍然大悟。

“相遇即是擦肩而过”

如果我们总是想着蚂蚁碰头后往回走,那么他们整体的轨迹将变得杂乱无章,确实很难理清头绪

然而,当蚂蚁碰面时,两个蚂蚁都已经被传染感冒了,他们是完全等价的。我们可以认为他们只是擦肩而过。

这样看来,每只蚂蚁只是从一个起点朝一个方向走到头而已

那么被传染感冒的,就是和蚂蚁同方向且在蚂蚁后面的以及和蚂蚁异方面且在蚂蚁前面的蚂蚁~

/*相遇即是擦肩而过*/ 
#include<stdio.h>
#include<stdlib.h>
int a[1000];
void qp(int n)
{
	int i,j,t;
	for(i=1;i<n;i++)
	for(j=1;j<=n-i;j++)
	if(abs(a[j])>abs(a[j+1]))
	{t=a[j];a[j]=a[j+1];a[j+1]=t;}
/*	
	for(i=1;i<=n;i++)
	printf("%d ",a[i]);
	printf("\n");
*/	
}
int main()
{
	int i,n,p,k;
	while(~scanf("%d",&n))
	{
		for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
		p=a[1];
		qp(n);
		for(i=1;i<=n;i++)
		if(a[i]==p)
		k=i;
		int sum=1;
		for(i=1;i<k;i++)
		if(a[i]>0)
		sum++;
		for(i=k+1;i<=n;i++)
		if(a[i]<0)
		sum++;
	    printf("%d\n",sum);
	}
	return 0;
}



  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值