【NOJ1143】【算法实验二】【DFS_回溯】字母转换


1143.字母转换

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

通过栈交换字母顺序。给定两个字符串,要求所有的进栈和出栈序列(i表示进栈,o表示出栈),使得字符串2在求得的进出栈序列的操作下,变成字符串1。输出结果需满足字典序。

例如TROT 到 TORT:

[
i i i i o o o o
i o i i o o i o
]

 

输入

给定两个字符串,第一个字符串是源字符串,第二个字符是目标目标字符串。

 

输出

所有的进栈和出栈序列,输出结果需满足字典序。


【2018/11/16第二版代码】

#include <iostream>
#include <stack>
#include <string>
using namespace std;

stack <char> s1;

string a,b;
int l;

int in,out; //进栈。出栈次数
int num;    //目前栈内元素个数

char ans[10001];    //存放答案

void dfs(int m);

int main()
{
    while(cin>>a>>b)    //多组测例
    {
        //cout<<a<<b;
        int la=a.length();
        int lb=b.length();

        cout<<'['<<endl;
        if(la==lb)  //若两字符串长度相同才深搜
        {
            in=out=num=0;
            l=la;
            dfs(0);
        }
        cout<<']'<<endl;
    }
    return 0;
}

void dfs(int m) //m指代第m次操作
{
    if(m==2*l)  //操作数(出栈次数+入栈次数)应该等于两倍的字符串长度
    {
        while(!s1.empty())  //清空栈
        {
            s1.pop();
        }

        int j=0,k=0;
        bool flag=true;
        for(int i=0; i<m; i++)
        {
            if(ans[i]=='i') //入栈操作
            {
                char c=a[j++];
                s1.push(c);
            }
            else    //出栈操作
            {
                char d=s1.top();
                if(d!=b[k++])   //若操作序列已不满足相等条件,那么跳出
                {
                    flag=false;
                    break;
                }
                s1.pop();
            }
        }
        if(flag)    //若操作序列满足相等条件,输出一组答案
        {
            for(int i=0; i<m; i++)
            {
                cout<<ans[i];
                if(i!=m-1)  //结尾无空格
                {
                    cout<<' ';
                }
            }
            cout<<endl;
        }
    }
    else
    {
        if(in<l)    //入栈次数应<=字符串长度
        {
            ans[m]='i'; //第m次操作为入栈

            in++;   //入栈次数+1
            num++;  //栈内元素+1
            dfs(m+1);   //下一步操作
            num--;  //还原
            in--;
        }
        if(out<l&&num>0)    //出栈次数应<=字符串长度,且栈内元素个数必须>0
        {
            ans[m]='o';
            out++;
            num--;
            dfs(m+1);
            num++;
            out--;
        }
    }
}

【2018/9/30第一版代码】:使用了tmp临时数组用来比较字符串a经操作后是否与字符串b相等

#include <iostream>
#include <stack>
#include <string.h>

using namespace std;

stack <char>s;

int length; //字符串长度
int in,out; //进栈/出栈次数

char start[1000];   //初始字符串
char target[1000];  //目标字符串

char tmp[1000];     //中间字符串

char step[2000];    //记录每一步的入栈/出栈操作

void dfs(int m);
bool ok();      //当前解能否符合要求
void output();  //输出一组解

int main()
{
    while(cin>>start>>target)
    {
        int length1=strlen(start);
        int length2=strlen(target);

        in=out=0;

        cout<<'['<<endl;
        if(length1==length2)
        {
            length=length1;
            dfs(0);
        }
        cout<<']'<<endl;
    }

    return 0;
}

void dfs(int m) //第m步操作,初始值为0
{
    if(m==length*2)
    {
        if(ok())
        {
            output();
        }
    }
    else
    {
        if(in<length)
        {
            in++;
            step[m]='i';
            dfs(m+1);
            in--;
        }
        if(out<in)
        {
            out++;
            step[m]='o';
            dfs(m+1);
            out--;
        }
    }
}

bool ok()       //当前解能否符合要求
{
    int i,j,k;
    for(i=0,j=0,k=0; i<length*2; i++)
    {
        if(step[i]=='i')
        {
            s.push(start[j++]);
        }
        else
        {
            tmp[k++]=s.top();
            s.pop();
        }
    }
    for(int i=0; i<length; i++)
    {
        if(tmp[i]!=target[i])
        {
            return false;
        }
    }
    return true;
}

void output()   //输出一组解
{
    int i;
    for(i=0; i<length*2-1; i++)
    {
        cout<<step[i]<<' ';
    }
    cout<<step[i]<<endl;
}

【后记】

1.这道题好难啊……可能因为没有学过数据结构,对栈和C++都不太熟悉,还一昧的想着优化剪枝……昨晚写这个被虐到凌晨,今天下午午觉睡醒了重新做才做出来……

2.啊啊啊啊啊今晚超级坑爹的把源码覆盖掉了。。。亲眼看到源码在自己眼前消失的感觉。。。太难受了,还好在oj上找到了QAQ……一定要备份啊备份!魂淡!

3.重写第二次的时候发现,写的还没第一次好ORZ。。。。string和char*、string和string.h、size和sizeof和strlen…太复杂了吧!!!

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值