其实此题在测试数据小的情况下可以用解决约瑟夫环的方法
但是因为此题数据很大(2^31),所以用解约瑟夫的方法肯定会爆内存解题的关键在于找出每次操作前后编号位置的变化关系
-----------------------------------------------------------------------------------------------------------------------------------------
采用递归的思路,任取一轮开始讨论,假设此时剩下m人
1,2,3,4,5......m
我们需要推出上一次第m个人的位置,由于是每第k个就杀掉,所以要还原上一次的队列就必须每两k-1个人就要补上1个人,
当前第m人前面有m-1人,所以要补上(m-1)/(k-1)个人,因此当前第m人在上一次队列中的位置是(m-1)/(k-1)+m
至此,关系已经推出,接下来是代码实现
#include<stdio.h>
int main()
{
int dfs(int n,int k);
int T;
int n,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
printf("%d\n",dfs(n,k));
}
return 0;
}
int dfs(int n,int k)
{
int num;
if(n==k)
{
return k;
}
num=dfs(n-n/k,k);
return ((num-1)/(k-1)+num);
}
-------------------------------------------------------------------------------------------------------------------------------------------
做此题时无意间想出的用数组解决约瑟夫环的方法(之前只学过链表的),不知道是不是很普遍的,
主要是利用两个数组交替存放剩下的队列,在此贴出来水水
#include<stdio.h>
#include<stdlib.h>
int a[100000000];
int b[100000000];
int main()
{
void kkk(int a[1],int b[],int na,int k);
int T,n,k;
scanf("%d",&T);
int i,j,na,nb;
while(T--)
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i)
{
a[i]=b[i]=i;
}
kkk(a,b,n,k);
}
return 0;
}
void kkk(int a[],int b[],int na,int k)
{
int nb=1;
int i;
for(i=1;i<=na;++i)
{
if(i%k!=0)
{b[nb]=a[i];nb++;}
}
nb--;
if(nb==k)
{
printf("%d\n",b[k]);
return;
}
else
{
kkk(b,a,nb,k);
}
}