ZZU数据结构与算法实验_0

ZZU数据结构与算法实验_0

问题描述

任给正整数 n n n k k k,将 1 1 1~ n n n成环形排列,按顺时针方向从 1 1 1开始计数;记满 k k k时输出该位置上的数字(并从环中删去该数字),然后从下一个数字开始计数,直到所有数字均被输出为止。例如当 n = 10 , k = 3 n=10,k=3 n=10,k=3时输出 3 , 6 , 9 , 2 , 7 , 1 , 8 , 5 , 10 , 4 3,6,9,2,7,1,8,5,10,4 3,6,9,2,7,1,8,5,10,4。试写一算法,对输入的任意正整数 n , k n,k n,k,输出相应的置换

Solve_0

用循环链表模拟整个计数、删数的过程
时间复杂度 O ( n ⋅ k ) O(n·k) O(nk)
代码:

#include<stdio.h>
#include<stdlib.h>
 
typedef struct Node {
	int data;
	struct Node* next;
}Node;
 

Node* Init_List(Node *head) {
	Node *p;
	head->data = 1;
	head->next = NULL;
	p = head;
 
	return p;
}
 
Node* push_back(Node *p, int n) {
	for (int i = 2; i <= n; i++) {
		Node *r = (Node*)malloc(sizeof(Node));
		r->data = i;
		r->next = NULL;
		p->next = r;
		p = r;
	}
	return p;
 
}
 
int main() {
	int n, k;
 	scanf("%d %d", &n, &k);
	Node *head, *p, *q, *r;
	head = q = r = (Node*)malloc(sizeof(Node));
 
	p = Init_List(head);
	p= push_back(p, n);
 
	p->next = head;
	p = p->next;
 
	while (p->next != p) {
		for (int i = 1; i < k; i++) {
			q = p;
			p = p->next;
			r = p;
		}
		printf("%d ", p->data);
		q->next = p->next;
		p = p->next;
		free(r);
	}
	printf("%d", p->data);
	return 0;
}

Solve_1

将环从 1 1 1~ n n n展开,我们定义一个变量p,记录当前所在位置,定义一个变量t,记录当前序列长度,每次删去第 ( p + k − 2 ) % t + 1 (p + k - 2) \% t + 1 (p+k2)%t+1直到删空,我们可以用树状数组储存序列,在树状数组上二分找到序列中第 x x x小的那个数,输出后从树状数组上删去即可
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码:

#include <stdio.h>

#define int long long

const size_t N = (size_t)1e6 + 5;

int n, k;
int tr[N];

int lowbit(int x) {
    return x & -x;
}

void ini() {
    for (int i = 0; i <= n; i++) {
        tr[i] = lowbit(i);
    }
}

void add(int pos, int x) {
    for (int i = pos; i < n; i += lowbit(i)) {
        tr[i] += x;
    }
}

int ffind(int k) {
    int ans = 0, now = 0;
    for (int i = 20; i >= 0; i--) {
        ans += (1 << i);
        if (ans >= n || tr[ans] + now >= k) ans -= (1 << i);
        else now += tr[ans]; 
    }
    return ans + 1;
}

void solve() {
    scanf("%d %d", &n, &k);
    ini();
    int p = 1, t = n;
    while(t) {
        p = (p + k - 2) % t + 1;
        int ans = ffind(p);
        add(ans, -1);
        printf("%d ", ans);
        t--;
    }
}   

signed main() { 
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值