2014年1月14日训练赛D题题解(栈+dfs)

题目

给出两个字符串s1和s2,如果s1能够通过栈的模拟得到s2,则输出详细的步骤,并且输出所有的可性操作。这里用'i'表示Push(进栈,插入一个元素),用'o'表示Pop(退栈,删除一个元素)。比如s1="TROT", s2="TORT",则可以有以下两种操作:i i i i o o o o和i o i i o o i o。



先部署好一切:


stack为模拟的栈,A为处理到的原始串的下标,B为目标串的下标,0表示当前处理第1个进出操作,seq记录进出的信息,也即最后要打印的io序列。

处理结束条件:


进出进出,n是字符串长度,有进必有出,所以当k==2n的时候,也就得到我们的进出序列。这时不再调用函数里,直接return。

题目要求的是字典序排列,也即又能进又能出的时候,先进,因为i比o靠前。进:



出:


这里可以看到为什么上面进的时候要top--和A--,这个是还原操作。

答案是,在当前步,我们还可能进行出操作。所以要还原现场。考虑进的时候,我们让top++和A++了,表明栈多了一个字符,同时处理完了原始串A位置上的字符。但当前步还可能是出操作,所以要复原刚进来dfs时的各变量的值,也即让栈弹出一个字符,即top--。认为还没处理完原始串A位置上的字符,也即进行A--。

总的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

int cmp(const void *_a,const void *_b){
  int *a=(int *)_a;
  int *b=(int *)_b;
  return *a-*b;
}

char s1[100],s2[100];

int n;
//stack表示一个栈,top表示当前栈顶,A表示原先的字符串当前考虑的字符下标
//B表示目标字符串当前考虑的字符下标
//seq,表示操作序列
void dfs(char* stack,int top,int A,int B,int k,char* seq){
  if(k==2*n){
    if(A==n && B==n){
      for(int i=0;i<k;i++){
        printf("%c ",seq[i]);
      }
      printf("\n");
    }
    return;
  }
  if(A<n){
    seq[k]='i';
    ++top;
    stack[top]=s1[A];
    A++;
    dfs(stack,top,A,B,k+1,seq);
    top--;
    A--;
  }
  //栈非空且当前栈弹出的字符,等于目标串头字符时
  if(top!=0 && stack[top]==s2[B]){
    seq[k]='o';
    char topCh=stack[top];
    top--;
    B++;
    dfs(stack,top,A,B,k+1,seq);
    stack[++top]=topCh;
    B--;
  }
}

void deal(){
  char stack[210];
  while(scanf("%s%s",s1,s2)==2){
    int top=0;
    printf("[\n");
    n=strlen(s2);
    int A=0,B=0;
    char seq[210];
    dfs(stack,top,A,B,0,seq);
    printf("]\n");
  }
}

int main(){
  freopen("in.txt","r",stdin);
  deal();
  return 0;
}

来,试试 这题(比上面的题要容易,但原理一样)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值