CCPC 2019 网络赛 1006 Shuffle Card

// 签到题,比赛时候写双向链表debug了半天,发现有更好方法,记录一下。
 

Shuffle Card HDU 6707

题意:

  有一 (n) 张卡片,编号 (1~n) ,给定初始编号排列和 (m) 次操作,每次操作将编号为 (s_i) 的卡片放到第一张上面。求最后卡片的编号序列。
 

思路:

  直接想法就是模拟,复杂度 (O(nm)) ,会T掉。如果采用双向链表储存编号,每次洗牌操作复杂度都是 (O(1)) ,总复杂度(O(m)),可行。比赛时候写链表少连了一条边调了半天
  双向链表交换两个节点太麻烦了,今天发现可以直接用,输出序列标出上面已拿出的卡片编号即可,复杂度 (O(n+m))
 

AC代码1:

 // 栈实现
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 100010;

bool vis[maxn];
int arr[maxn];
vector<int> S;

int main() {
	int n, m;
	cin>>n>>m;
	for(int i=0;i<n;i++) {
		scanf("%d", &arr[i]);
	}
	for(int i=n-1;i>=0;i--) {
		S.push_back(arr[i]);
	}	
	while(m--) {
		int card; scanf("%d", &card);
		S.push_back(card);
	}
	int left = n;
	while(!S.empty() && left) {
		int now = *--S.end();
		if(!vis[now]) {
			printf("%d ", now);
			vis[now] = 1;
			--left;
		}
		S.pop_back();
	}
	return 0;
}

AC代码1:

 // 双向链表实现
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 100010;

struct node {
	int pre, next;
}cards[maxn];
int head;

int arr[maxn];

int main() {
	int n, m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		scanf("%d", &arr[i]);
	}

	head = arr[1];
	cards[arr[1]].pre = -1;
	cards[arr[n]].next = -1;
	for(int i=1;i<n;i++) {
		cards[arr[i]].next = arr[i+1];
		cards[arr[i+1]].pre = arr[i];
	}
	

	while(m--) {
		int c; scanf("%d", &c);
		if(c==head) continue;

		int h = c;	// 新的头结点
		int pre = cards[c].pre;
		int next = cards[c].next;

		if(pre!=-1)
			cards[pre].next = next;
		if(next!=-1)
			cards[next].pre = pre;

		cards[c].next = head;
		cards[head].pre = c;   // 别忘了这一行!!!
		cards[c].pre = -1; 
		head = c;

	}

	int p = head;
	while(p!=-1) {
		printf("%d ", p);
		p = cards[p].next;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/izcat/p/11424120.html