• 约瑟夫环


    最近又看到了当时困惑自己很久的约瑟夫,本质上来说有点类似于dp,推导出f(n)与f(n-1)的转移关系递推求解。

    下面是最经典的约瑟夫问题,什么?链表模拟?  不存在的>_<

    https://vjudge.net/problem/51Nod-1073

    首先,将n个人编号为: 0,1,2,3........k-1,k,k+1........n-1,

    第一轮结束之后第k个人,也就是k-1将出列,剩下的人: 0,1,2,3.........k-2, k, k+1.......n-1

    下一轮从k开始我们进行重新编号,将上面的编号为:   n-k,n-k+1,n-k+2,n-k+3.............., 0,.1,.........n-k-1,

    我们如果知道了这一轮存活下来的人对应的编号是y,那么他本来的编号就是 x=(y+k)%n

    由此引出递推式 f(n)=(f(n-1)+k)%n | f(1)=0

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 int main()
     5 {
     6     int n,k,i,j;
     7     while(cin>>n>>k){
     8         int x=0;
     9         for(i=2;i<=n;++i)
    10             x=(x+k)%i;
    11         cout<<x+1<<endl;
    12     }
    13     return 0;
    14 }

    有关这个问题的变形问题也是众多,下面我挑了一些来练习,

    https://vjudge.net/problem/UVA-1394

    题意,给出n,k,m表示,第一次先出队第m个人,然后从后面的人开始数到k的出列接着从1开始数,

    和原来的有了一点变化就是不是从第一个人开始数了,而是先出队第m然后从m+1开始,不过只有第一轮的和后面的公式不一样我们只要算出f(n-1)再推f(n)就好了。

    我们将第m人出列后从新对余下的(n-1)人编号,f(n-1)=(f(n-2)+k)%(n-1);  设x=f(n-1),则最后的答案  ans=(x+m)%n+1;

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 int main()
     5 {
     6     int n,k,i,j,m;
     7     while(cin>>n>>k>>m&&(n+k+m)){
     8         int x=0;
     9         for(i=2;i<n;++i)
    10             x=(x+k)%i;
    11         x=(m+x)%n;
    12         if(x<0) x+=n;
    13         cout<<x+1<<endl;
    14     }
    15     return 0;
    16 }

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

    这个就是每次出队是k倍数的人,找到队尾之后将再次从队首开始数1,与约瑟夫有些不同,但不变的是公式推倒的过程。

    想要知道f(n),我们不妨先假设得到了x=f(n-1),这里的n表示是第几轮从头开始,我们如果将这个x转为原本的编号呢,如果我们知道他前面死了几个人的话,

    直接让x加上这个人数就好了,因为数到k就死一个,也就是说x前面有几个(k-1)就表示上一轮x前面淘汰的人,加上就好,最后边界f(k,k)=k

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 int dfs(int n,int k)
     5 {
     6     if(n==k) return k;
     7     int x=dfs(n-n/k,k);
     8     return x+(x-1)/(k-1);
     9 }
    10 int main()
    11 {
    12     int n,k,i,j,m;
    13     cin>>m;
    14     while(m--){
    15         cin>>n>>k;
    16         cout<<dfs(n,k)<<endl;
    17     }
    18     return 0;
    19 }
  • 相关阅读:
    P1962 斐波那契数列(矩阵加速DP)
    P1939 【模板】矩阵加速(数列)
    剑指04.重建二叉树
    剑指03.从尾到头打印链表
    剑指02.替换空格
    剑指01.二维数组中的查找
    Python绘图学习笔记(待完善)
    时间观念 目标观念
    购房交税
    可以不做会计,但是不能不懂会计
  • 原文地址:https://www.cnblogs.com/zzqc/p/7327996.html
Copyright © 2020-2023  润新知