uva 133 The Dole Queue

本文探讨了一种优化解决约瑟夫环问题的方法,通过使用布尔数组模拟,避免了传统方法中复杂的链表操作,提高了算法效率。详细介绍了问题背景、核心算法原理、代码实现以及实际应用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题我用的静态链表,感觉还是比较绕的,,有一个小trick,比如当k走到a位置,m走到b位置,而a的下一个位置就是b,这就必须特殊处理了


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
using namespace std;
#define N 100
#define dbag printf("%d\n", n);
int L[100], R[100];
void link(int a, int b)
{
    R[a] = b;
    L[b] = a;
}
int main()
{
    int n, k, m;
    while(scanf("%d%d%d", &n, &k, &m))
    {
        if(n==0)break;
        for(int i = 2; i <= n; i++)
            L[i] = i-1;
        L[1] = n;
        for(int i = 1; i <= n-1; i++)
            R[i] = i+1;
        R[n] = 1;
        k = (k-1)%n; m = (m-1)%n;
        int cnt = n;
        int posk = 1, posm = n;
        while(cnt>=1)
        {
            int tk = 0;
            while(tk<k)
            {
                posk = R[posk];
                tk++;
            }
            int tm = 0;
            while(tm<m)
            {
                posm = L[posm];
                tm++;
            }
            if(posk!=posm)
            {
                cnt-=2;
                printf("%3d", posk);
                if(cnt==0)
                    {printf("%3d\n", posm);break;}
                else
                    printf("%3d,", posm);
                int prek = posk; posk=R[posk];
                int prem = posm; posm=L[posm];
                if(posk==prem&&cnt>=2)  //特殊情况,当posk走到下一位置恰好是m当前的位置
                {
                    posk=R[posk];
                    posm=L[posm];
                    link(L[prek], R[prem]);
                }
                else
                {
                    link(L[prek], R[prek]);
                    link(L[prem], R[prem]);
                }
            }
            else
            {
                cnt -= 1;
                if(cnt==0)
                    {printf("%3d\n", posk);break;}
                else
                    printf("%3d,", posk);
                int prek = posk; posk=R[posk];
                int prem = posm; posm=L[posm];
                link(L[prek], R[prek]);
            }
        }
    }
    return 0;
}



后面又想了下,,上面的做法太操蛋,,换了个写法

//这种约瑟夫环问题,直接用bool数组模拟,不用考虑删除数,数之间的链接问题
//因为用bool标记已访问,在逻辑上顺序是没变的
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
using namespace std;
#define N 200
int main()
{
    int n, k, m;
    while(scanf("%d%d%d", &n, &k, &m))
    {
        if(n==0)break;
        bool vis[N];
        memset(vis, false, sizeof(vis));
        int cnt = n;
        k = (k-1)%n+1; m = (m-1)%n+1;
        int posk = -1, posm = n;
        while(cnt>0)
        {
            int tk = 0, tm = 0;
            while(tk<k)
            {
                posk++; posk%=n;
                if(!vis[posk])
                    tk++;
            }
            while(tm<m)
            {
                posm--;if(posm<0)posm = n-1;
                if(!vis[posm])
                    tm++;
            }
            if(posm==posk)
            {
                cnt-=1;
                if(cnt==0)
                    printf("%3d\n", posk+1);
                else
                    printf("%3d,", posk+1);
                vis[posm]=true;
            }
            else
            {
                cnt-=2;
                if(cnt == 0)
                    printf("%3d%3d\n", posk+1, posm+1);
                else
                    printf("%3d%3d,", posk+1, posm+1);
                vis[posk] = true; vis[posm] = true;
            }
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值