题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1443
题目大意:
一共有2k个人,分别为k个好人和k个坏人,现在我们需要每隔m个人把坏人挑出来,但是条件是最后一个坏人挑出来前不能有好人被挑出来。。问最小的m是多少
解题思路:
典型的约瑟夫问题。这道题也不算多难,只要肯好好想,思路是一定会有的。但是实现起来确实有一定的难度,弄了2个小时,当k小于9都能跑出来,再大程序就死了。。。。因为数太大,我的程序不够优化,所以就OVER了。。。
搜了下解题报告,发现思路跟我一样,就是处理的时候用了一定的技巧。我是用一个数组标记已经被挑出去的坏人,每次只能一个一个检查,这样铁定要TLE,但是也想不出什么其他方法。。悲剧。。。。网上的思路就是挑出去一个坏人,总人数就减1,总之不是太明白,弄清楚再来解释吧。。。。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int res[16];
int fun(int n)
{
int ans, flag, sum;
if(res[n])
return res[n];
else
{
for(ans = n + 1; ; ++ans)
{
flag = 0;
sum = 2 * n;
for(int j = ans; ; j += ans - 1) //人数减1
{
if(j > sum)
j = j % sum ? j % sum : sum; //人数减1
if(j <= n)
break;
else
sum--;
if(sum == n)
{
flag = 1;
break;
}
}
if(flag)
{
res[n] = ans;
return res[n];
}
}
}
}
int main()
{
int n;
while(scanf("%d", &n) && n)
{
printf("%d\n", fun(n));
}
return 0;
}
自己的挫代码。。。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool visit[16];
int main()
{
//freopen("Input.txt", "r", stdin);
int k, m, count, now;
while(scanf("%d", &k) && k)
{
for(m = k + 1; ; ++m)
{
memset(visit, false, sizeof(visit));
count = 2 * k;
now = 0;
while(count > k)
{
for(int j = (now + 1), sum = 0; sum < m; ++j)
{
if(j > 2 * k)
j %= (2 * k);
if(!visit[j])
{
sum++;
now = j;
}
}
if( now > k && !visit[now] )
{
visit[now] = true;
count--;
}
if(now <= k)
break;
}
if(count == k)
break;
else
continue;
}
printf("m的值为:%d\n", m);
}
return 0;
}