数组模拟单链表
例题6-4 Broken Keyboard (a.k.a. Beiju Text) UVA - 11988
这道题目可以直接用STL中list双向链表来做,思路和代码都很简单易想。也可以用数组模拟链表(不易懂)。
之所以不用vector是因为插入删除比较慢慢慢
AC代码(一):
STL的list版本
#include<iostream>
#include<list>
#include<string>
using namespace std;
int main()
{
string s;
while(cin>>s){
list<char>l;
list<char>::iterator it=l.begin();
for(int i=0;i<s.length();i++){
if(s[i]=='[') it=l.begin();
else if(s[i]==']') it=l.end();
else{
it=l.insert(it,s[i]);
it++;
}
}
for(it=l.begin();it!=l.end();it++)
cout<<*it;
cout<<endl;
}
return 0;
}
AC代码(二):
数组模拟链表版本
//数组模拟链表
#include<stdio.h>
#include<string.h>
const int maxn=100000+5;
int next[maxn];//next[i]表示链表中第i个结点下一个结点的编号
char s[maxn];
int cur;//当前光标所在位置,即指向当前结点的右侧
int last;//当前最后一个结点的编号
int main()
{
//s[0]设置为类似链表的头结点,元素从下标1开始编号
while(scanf("%s",s+1)!=EOF){
int len=strlen(s+1);
cur=last=0;
next[0]=-1;//这里-1仅仅是一个标记,表示起初链表的头结点指向的数值
//类似于指针链表初始化时候linklist->next=NULL
for(int i=1;i<=len;i++){
if(s[i]=='[') cur=0;//光标定位到开始,指向第0个元素(假想的头结点)的右侧
else if(s[i]==']') cur=last;//光标定位到最后一个元素,指向最后一个元素的右侧
else{
//插入新节点i,类似于链表中创建一个节点i,让他的next指向当前链表头(cur)的next
//再让当前链表头的next指向节点i
//和普通链表不同的是这里的链表头cur会变,但是next[0]永远是第一个字符哦
next[i]=next[cur];
next[cur]=i;
if(cur==last) last=i;//如果现在的cur=last,插入新节点后,更新last,手写易明白
//由于cur可能会回到头变成0,所以这个操作技巧很好
cur=i;//插入一个新节点后,cur自然后移,指向当前节点的右侧
}
}
//上述过程完成了建立一个链表的过程,next[0]的值就是第一个字符的下标,next[1]就是第2个节点
//的下标,以此类推,最后一个节点的next必然是-1,想想链表建立过程,依次往后指,这一点应该很明白
for(int i=next[0];i!=-1;i=next[i])
printf("%c",s[i]);
printf("\n");
}
return 0;
}
C语言代码(超时为何?):
#include<stdio.h>
#include<string.h>
const int maxn=100000+5;
char s[maxn];
typedef struct LINK{
LINK *next;
LINK *rear;
LINK *cur;
char c;
}node,*linklist;
void linklist_init(linklist &lis){
lis=new node;
lis->rear=lis;
lis->next=NULL;
lis->cur=lis;
}
void linklist_insert(linklist &lis,char e){
node *p=new node;
p->next=lis->cur->next;
p->c=e;
lis->cur->next=p;
if(lis->cur==lis->rear) lis->rear=p;
lis->cur=p;
}
int main()
{
while(scanf("%s",s)!=EOF){
linklist lis;
linklist_init(lis);
for(int i=0;i<strlen(s);i++){
if(s[i]=='[') lis->cur=lis;
else if(s[i]==']'){lis->cur=lis->rear;}
else{
linklist_insert(lis,s[i]);
}
}
node *tmp=lis;
while(tmp->next){
printf("%c",tmp->next->c);
tmp=tmp->next;
}
printf("\n");
}
return 0;
}
数组模拟双向链表
例题6-5 Boxes in a Line UVA - 12657
直接给出参考刘汝佳《算法竞赛入门经典》(第2版)代码参考:
#include<cstdio>
const int maxn=100000+5;
int n,m;
int left[maxn],right[maxn];
int kase=0;
void link(int l,int r){
right[l]=r;
left[r]=l;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++){
left[i]=i-1;
right[i]=(i+1)%(n+1);
}
left[0]=n;right[0]=1;
int op,x,y;
bool inv=0;
while(m--){
scanf("%d",&op);
if(op==4) inv=!inv;
else{
scanf("%d%d",&x,&y);
if(op==3 && right[y]==x){int t=x;x=y;y=t;}//x,y相邻的情形统一变为y在x右侧
//下面这个复合语句坑我了,下面这么写是对的,下面的复合语句全部用if,if是错的
{
if(op==2 && inv) op=1;//逆转后,右边变左边,左边变右边
else if(op==1 && inv) op=2;
}
if(op==1 && x==left[y]) continue;
if(op==2 && x==right[y]) continue;
int lx=left[x],rx=right[x],ly=left[y],ry=right[y];//这样已经保存了x,y的左右值哦,这样很方便后续操作
if(op==1){
link(lx,rx);link(ly,x);link(x,y);
}
else if(op==2){
link(lx,rx);link(y,x);link(x,ry);
}
else if(op==3){
//分为两种情形,x,y相邻与否
if(right[x]==y){
link(lx,y);link(y,x);link(x,ry);
}
else{
link(lx,y);link(y,rx);
link(ly,x);link(x,ry);
}
}
}
}
int j=0;
long long int ans=0;
for(int i=1;i<=n;i++){
j=right[j];
if(i%2==1) ans+=j;
}
if(inv && n%2==0) ans=(long long)n/2*(n+1)-ans;
printf("Case %d: %lld\n",++kase,ans); }
return 0;
}