题目不难,属于模拟类型的题目,需要比较仔细地处理各种边界情况。估计题目的本意是想让我们实现一个双向循环链表,我看了下N的值最大20,所以想先用数组实现试试,基本思路也是在数组里双向循环,删除的元素标记下;双向循环链表实现就比较好理解了,但是实现起来有些麻烦,指针神马的很容易搞错,需要非常仔细。
开始提交超时了,原因分析了下是因为:虽然N的值不大,但是k和m可以很大,所以找下k/m个的时候需要mod一下当前queue的size。
数组实现:
#include<stdio.h>
#define MAX 30
/*
* status 0 means normal, status 1 means deleted
* */
typedef struct Node {
int num;
int status;
} Node;
/*
* startIdx1,startIdx2 mark the starting point of each round of picking.
* */
typedef struct Queue {
Node elements[MAX];
int size;
int startIdx1;
int startIdx2;
} Queue;
int n, k, m;
Queue queue;
void printQue() {
int i;
for (i = 0; i < n; i++) {
printf("%d:[%d,%d] ", i, queue.elements[i].num,
queue.elements[i].status);
}
printf("size:%d\n", queue.size);
}
int getNextIdx(int current) {
int result = current + 1;
if (result == n)
result = 0;
return result;
}
int getPreIdx(int current) {
int result = current - 1;
if (result < 0)
result = n - 1;
return result;
}
int pickFirst(int idx) {
int currentIdx = idx;
int count = 1;
int num = k % queue.size;
if (num == 1 || (queue.size == 1))
return currentIdx;
if (num == 0)
num = queue.size;
while (1) {
currentIdx = getNextIdx(currentIdx);
if (queue.elements[currentIdx].status != 1)
count++;
if (count == num) {
return currentIdx;
}
}
}
int pickSecond(int idx) {
int currentIdx = idx;
int count = 1;
int num = m % queue.size;
if (num == 1 || (queue.size == 1))
return currentIdx;
if (num == 0)
num = queue.size;
while (1) {
currentIdx = getPreIdx(currentIdx);
if (queue.elements[currentIdx].status != 1)
count++;
if (count == num) {
return currentIdx;
}
}
return 0;
}
void pick() {
int firstPick = pickFirst(queue.startIdx1);
int secondPick = pickSecond(queue.startIdx2);
queue.elements[firstPick].status = 1;
queue.elements[secondPick].status = 1;
if (firstPick == secondPick)
queue.size -= 1;
else
queue.size -= 2;
if (firstPick != secondPick)
printf("%3d%3d", queue.elements[firstPick].num,
queue.elements[secondPick].num);
else
printf("%3d", queue.elements[firstPick].num);
if (queue.size > 0)
printf(",");
else
printf("\n");
if (queue.size <= 0)
return;
int nextStartIdx1 = getNextIdx(firstPick);
while (queue.elements[nextStartIdx1].status == 1)
nextStartIdx1 = getNextIdx(nextStartIdx1);
int nextStartIdx2 = getPreIdx(secondPick);
while (queue.elements[nextStartIdx2].status == 1)
nextStartIdx2 = getPreIdx(nextStartIdx2);
queue.startIdx1 = nextStartIdx1;
queue.startIdx2 = nextStartIdx2;
}
int main() {
/* setbuf(stdout,NULL);*/
while (scanf("%d%d%d", &n, &k, &m) != EOF) {
if (n == 0)
break;
queue.size = n;
queue.startIdx1 = 0;
queue.startIdx2 = n - 1;
int i;
for (i = 0; i < n; i++) {
queue.elements[i].num = i + 1;
queue.elements[i].status = 0;
}
while (queue.size > 0) {
pick();
}
}
return 0;
}
链表实现:
#include<stdio.h>
#include<stdlib.h>
#define MAX 30
struct Node;
typedef struct Node* PtrToNode;
typedef struct Node {
int num;
PtrToNode next;
PtrToNode pre;
} Node;
typedef struct Queue {
PtrToNode head;
int size;
PtrToNode startIdx1;
PtrToNode startIdx2;
} Queue;
int n, k, m;
Queue queue;
Queue *que = &queue;
void printQueue() {
int i;
PtrToNode cur = que->head;
for (i = 0; i < que->size; i++) {
printf("%d ", cur->num);
cur = cur->next;
}
printf("size:%d,idx1:%d,idx2:%d", que->size, que->startIdx1->num,
que->startIdx2->num);
printf("\n");
}
void makeQueue() {
PtrToNode head = (PtrToNode) malloc(sizeof(Node));
head->num = 1;
head->next = head;
head->pre = head;
que->head = head;
que->size = n;
que->startIdx1 = head;
que->startIdx2 = head;
if (n == 1)
return;
PtrToNode pre = head;
int i;
for (i = 1; i < n; i++) {
PtrToNode current = (PtrToNode) malloc(sizeof(Node));
current->num = i + 1;
current->pre = pre;
pre->next = current;
if (i == n - 1) {
current->next = head;
head->pre = current;
}
pre = current;
}
que->startIdx1 = head;
que->startIdx2 = head->pre;
}
PtrToNode getNextNNode(PtrToNode p, int n) {
int i;
int size = n % que->size;
PtrToNode result = p;
for (i = 0; i < size; i++) {
result = result->next;
}
return result;
}
PtrToNode getPreNNode(PtrToNode p, int n) {
int i;
int size = n % que->size;
PtrToNode result = p;
for (i = 0; i < size; i++) {
result = result->pre;
}
return result;
}
/*
* type 0 means removing the first pick.
* type 1 means removing the second pick.
* type 2 means removing the same item when first pick equals second pick.
*
* */
int removeNode(PtrToNode p, int type) {
if (p == NULL )
return -1;
int num = p->num;
if (p == que->head)
que->head = p->next;
if (p == que->startIdx1)
que->startIdx1 = p->next;
if (p == que->startIdx2)
que->startIdx2 = p->pre;
if (type == 2) {
que->startIdx1 = p->next;
que->startIdx2 = p->pre;
} else if (type == 0) {
que->startIdx1 = p->next;
} else {
que->startIdx2 = p->pre;
}
p->pre->next = p->next;
p->next->pre = p->pre;
free(p);
que->size--;
return num;
}
void pick() {
PtrToNode first = getNextNNode(que->startIdx1, k - 1);
PtrToNode second = getPreNNode(que->startIdx2, m - 1);
int one, two;
if (first == second) {
one = two = removeNode(first, 2);
} else {
one = removeNode(first, 0);
two = removeNode(second, 1);
}
if (one != two)
printf("%3d%3d", one, two);
else
printf("%3d", one);
if (que->size > 0)
printf(",");
else
printf("\n");
}
int main() {
/* setbuf(stdout,NULL);*/
while(scanf("%d%d%d",&n,&k,&m)!=EOF) {
if(n==0)
break;
makeQueue();
while(que->size>0) {
pick();
}
}
return 0;
}
本文详细探讨了使用数组和双向循环链表实现的选择算法,旨在高效解决给定数值集合中第k个和第m个元素的挑选问题。通过深入分析和优化,确保了算法在复杂度上的优化,特别针对N值较大但k和m值可能很大的场景进行了针对性优化。
280

被折叠的 条评论
为什么被折叠?



