题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1443
题目大意:
一共有2k个人,分别为k个好人和k个坏人,现在我们需要每隔m个人把坏人挑出来,但是条件是最后一个坏人挑出来前不能有好人被挑出来。。问最小的m是多少。k最大为13.
思路:
由于k的数值较小,直接打表就行。
对于约瑟夫环问题一般都是由0-n-1的下标,并且start = (start + m - 1)% n(n为当前的人数,n是会不断地变化的)这里的start是下标!!!不是具体的数值
举个例子:
6个人步数为5,初始化,start = 0
第一次:start = 0 + 5 - 1 % 6 = 4,下标为4的编号剔除
下标:0 1 2 3 4 5
编号:1 2 3 4 5 6
第二次:start = 4 + 5 - 1 % 5 = 3,下标为3的编号剔除
下标:0 1 2 3 4
编号:1 2 3 4 6
第三次:start = 3 + 5 - 1 % 4 = 3,下标为3的编号剔除
下标:0 1 2 3
编号:1 2 3 6
这里表示的都是下标的变化,题目要求前k个人不能先被剔除,只要下标start >= k一直成立就可以保证不会剔除前k个。因为如果每次的start >= k,说明提出的编号一定是>=k的(这里编号为k表示第k+1个人)
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 typedef long long ll; 6 const int maxn = 1e5; 7 ll a[25]; 8 void init(int k) 9 { 10 for(int ans = 0; ; ans++)//枚举步数 11 { 12 int start = 0; 13 int n = 2 * k;//2*k个人 14 bool ok = 1; 15 while(n > k)//输出前n个人即可 16 { 17 start = (start + ans - 1) % n;//这是下标,不是具体的数值,但是此处的下标必须大于等于k,这样才能保证前k个人不被剔除 18 //cout<<start<<endl; 19 if(start < k)//下标 < k,说明输出的一定是前k个人中的某一个 20 { 21 ok = 0; 22 break; 23 } 24 else n--;//满足的话,人数减一 25 } 26 if(ok) 27 { 28 a[k] = ans; 29 return; 30 } 31 } 32 return; 33 } 34 int main() 35 { 36 int n; 37 for(int i = 1; i <= 13; i++)init(i); 38 while(cin >> n && n) 39 { 40 cout<<a[n]<<endl; 41 } 42 return 0; 43 }
约瑟夫环传送门(等写到那个地方就开启传送门)