题目大意:
有k个好人跟k个坏人按顺序坐着,然后按第m个杀人,求出把坏人全部先杀光的m的最小值。 0<k<14。典型的约瑟环问题。
解题思路:
一开始看见数据量那么小,还以为暴力一定可以出来,结果,好吧,当k为0以上时,时间大得惊人,自己暴力的方法还是有很大问题啊。
比较标准的做法是:在这么多个人中,始终用start跟end来确定好人那个序列的位置。
比如一开始是1 2 3 4 5 6,那么start = 0,end = 3(从0开始计数)当m等于5的时候,kill后就剩下1 2 3 4 6 ,重新拍下序列变成 6 1 2 3 4 ,这时候
start = ((start-m)%n+n)%n;
end = ((end-m)%n+n)%n;
n是当前剩下的人数。定完位置之后,kill的位置为kill = (m-1)%n;
这样就可以做了。
AC代码:
#include
using namespace std;
bool joseph(int k, int m)
{
int start = 0, end = k - 1; //定位,定好人的位置
int kill;//杀人的序号
for(int n = 2 * k; n > k; n--) //n代表人数
{
kill = (m - 1) % n;
if(kill >= start && kill <= end)
{
return false;
}
start = ((start - m) % n + n) % n;//定位,加n模n是为了防止负数
end = ((end - m) % n + n) % n;
}
return true;
}
int main(void)
{
int f[14];
for(int i = 1; i < 14; i++)
for(int j = 1; ; j++)
{
if(joseph(i, j))
{
f[i] = j;
break;
}
}
int k;
while(scanf("%d", &k), k)
{
printf("%d\n", f[k]);
}
return 0;
}
TLE代码:
#include
using namespace std;
const int MAX = 30;
const int M = 100005;
int main(void)
{
int pe[MAX];
for(int k = 11; k < 14; k++)
{
bool mark[MAX];
for(int i = 0; i <= k; i++)
pe[i] = 1;
for(int i = k + 1; i <= 2 * k; i++)
pe[i] = 2;//bad guys
int min = 0;//结果
bool flag = false;
for(int m = 1; ; m++)
{
int count = 0, index = 1;
int bad = k;//坏人
//int m = 30;
memset(mark, false, sizeof(mark));
while(1)
{
if(mark[index] == true)
{
if(index == 2 * k) //指向的移动
{
index = 1;
}
else
index++;
continue;
}
count++;
if(count == m)
{
if(pe[index] == 1)//杀了好人
break;
else
{
mark[index] = true;
bad--;
if(bad == 0)
{
min = m;
flag = true;
break;
}
}
count = 0;//重新计数
}
if(index == 2 * k) //指向的移动
{
index = 1;
}
else
index++;
}
if(flag)
break;
}
//for(int i = 1; i <= 2*k; i++)
// printf("%d ", mark[i]);
//printf("\n");
printf("%d\n", min);
}
return 0;
}