1051 接龙游戏

题目连接

http://www.wikioi.com/problem/1051/

题意:给你n个字符串(1<=n<=10^5),查找最长的接龙数,能够接龙的条件是:前一个串是本串的前缀,例如 a --->ab这样就算接龙,但是这里串相同不算接龙,例如

a---->aaa----aaa 这样的接龙长度算2,然后输出这些串最长能够得到的接龙,输出这个数就ok了;

一开始看到这题的时候,因为这里的接龙条件是前一个串是后一个串的前缀,就想到了使用字典树来做,因为使用每一个单词了建立字典树,将下一个单词添加进树时,能够得到之前单词,如果之前的单词是这个单词的前缀,这个单词在进行添加进字典树的时候,一定会进过这条路径。

然后解决这个问题使用的方法是:标记每个单词,当下一个单词经过了这个条路径,得到当前的这个标记,然后本单词在这个基础上加1,在这里要注意重复单词的出现。

然后记录其中最大的标记数。最后输出这个max

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

typedef struct data{

    int t;
    data *next[26];
    data()
    {
        t = 0;
        for(int i = 0;i < 26; i++)
            next[i]= NULL;
    }
}data;

data *head;

int add(char *ch)
{
    if(head == NULL)
        head = new data();
    data *p = head;
    int t = 0;
    int tmp;
    bool flag = true;
    for(int i = 0; i < strlen(ch); i++)
    {
        flag = true;
        tmp = ch[i] -'a';
        if(p->next[tmp] == NULL)
            p->next[tmp] = new data();
        else
            {
                t = t > p->next[tmp]->t ? t : p->next[tmp]->t;
                flag = false;
            }
        p = p->next[tmp];
    }
    if(flag)
        p->t = ++t;

    return p->t;
}
void print(data *p)
{
    for(int i = 0; i < 26; i++)
    {
        if(p->next[i] != NULL)
            {
                printf("%c %d
",i+'a',p->next[i]->t);
                print(p->next[i]);
            }

    }
}
int main()
{
    int n;
    scanf("%d",&n);
    char ch[55];
    int max = 0;
    while(n--)
    {
        scanf("%s",ch);
        int t = add(ch);
        max = max > t ? max : t;
    }
   // print(head);
    printf("%d
",max);
    return 0;
}

 本代码在wikioi中得分80,内存超了,这个10^5个单词在创建字典树时内存消耗太大。。。。。纠结啊----------------------------

后来看了一下有人发的解题报告:

思路是,首先将这些单词进行字典序排序,然后使用一个栈来保存这个接龙,这个字典序排序貌似有两种排序,不知道是不是,但是在这里使用的排序方法是:

比较单词的每一个位置,字典序小的返回true,大的返回false,当有一个单词比较完后还没有结果,则长度短者返回true 长者false

自定义排序代码

typedef struct data{
    string s;
}data;

bool cmp(data x,data y)
{
    int len =  x.s.length() < y.s.length() ? x.s.length(): y.s.length();
    for(int i = 0; i < len; i++)
    {
        if(x.s[i] < y.s[i])
            return true;
        else if(x.s[i] > y.s[i])
            return false;
    }
   if(x.s.length() < y.s.length())
        return true;
    else return false;
}

 这样排序后前缀相同的单词都紧挨着了,然后使用栈来保存这个接龙,当单词将要入栈时,栈顶单词是该单词的前缀则进栈,不是则一直从栈中寻找,直到满足条件或是这个栈为空了,然后将这个单词入栈,在处理入栈的同时记录最长的接龙数。最后输出这个max就是答案,但是栈中保存的数据不一定是这个最长接龙的单词,这里已没有要求得到这个接龙。所以这里就不用考虑了。嘻嘻解决-----OK

代码:

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

typedef struct data{
    string s;
}data;

bool cmp(data x,data y)
{
    int len =  x.s.length() < y.s.length() ? x.s.length(): y.s.length();
    for(int i = 0; i < len; i++)
    {
        if(x.s[i] < y.s[i])
            return true;
        else if(x.s[i] > y.s[i])
            return false;
    }
   if(x.s.length() < y.s.length())
        return true;
    else return false;
}
data ch[100007];

int main()
{
    int n;
   cin>>n;
    for(int i = 0; i < n; i++)
        cin>>ch[i].s;

    sort(ch,ch+n,cmp);
    stack<data> mystatck;
    int max = 1;
    mystatck.push(ch[0]);
    data tmp;
    for(int i = 1; i < n; i++)
      {
            tmp = mystatck.top();
            if(ch[i].s.find(tmp.s,0) == 0)
                {
                    if(tmp.s.length() != ch[i].s.length())
                        mystatck.push(ch[i]);
                }
            else
            {
                while( !mystatck.empty()){
                    tmp = mystatck.top();
                    if(ch[i].s.find(tmp.s,0) == 0)
                        break;
                    mystatck.pop();
                }
                mystatck.push(ch[i]);
            }
        max = max > mystatck.size() ? max : mystatck.size();
       // cout<<mystatck.size()<<endl;
      }
    cout<<max<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/yyroom/p/3726545.html