0
点赞
收藏
分享

微信扫一扫

poj-2001

#include <stdio.h>
 #include <string.h>
 #include <vector>
 #include <string>
 #include <cstdlib>
 #include <iostream>

 using namespace std;

 const int CHAR_NUM = 26;

 struct tireNode{
     char val[22];
     struct tireNode * tireChildNode[CHAR_NUM];
     int appearTime;
     int byTime;
     int childNum;
     int index;
 };

 class stringInfo {
 public:
     string orginal;
     string abbv;
     stringInfo(const string & str): orginal(str), abbv("") {
     }
 };
 typedef struct stringInfo stringInfo;
 typedef struct tireNode tireNode;

 vector<stringInfo> V1;

 tireNode * tireTreeHead;

 void buildTireTree(char * word, int index) {
     if (!tireTreeHead) {
         tireTreeHead = (tireNode *)malloc(sizeof(tireNode));
         memset(tireTreeHead, 0, sizeof(tireNode));
     }
     int wordLength = strlen(word);

     tireNode * currentNode = tireTreeHead;

     for (int i = 0; i < wordLength; i++) {
         if (!currentNode->tireChildNode[word[i]-'a']) {
             currentNode->tireChildNode[word[i]-'a'] = (tireNode *)malloc(sizeof(tireNode));
             memset(currentNode->tireChildNode[word[i]-'a'], 0, sizeof(tireNode));
             strcpy(currentNode->tireChildNode[word[i]-'a']->val, currentNode->val);
             currentNode->childNum++;
             currentNode->tireChildNode[word[i]-'a']->val[strlen(currentNode->val)] = word[i];
             currentNode->tireChildNode[word[i]-'a']->index = index;
         }
         currentNode = currentNode->tireChildNode[word[i]-'a'];
         (currentNode->byTime)++;
     }
     (currentNode->appearTime)++;
     // printf("build %s %d\n", currentNode->val, currentNode->appearTime);
 }

 void getShortsetPrefix(tireNode * currentNode) {
     if (!currentNode) {
         return;
     }
     if (currentNode->byTime == 1) {
         // printf("1 %d %s %s\n", currentNode->index, V1.at(currentNode->index).orginal.c_str(), currentNode->val);
         V1.at(currentNode->index).abbv = currentNode->val;
         return;
     }
     // if (currentNode->appearTime) {
     //     // printf("%s %s\n", currentNode->val, possiblePrefix.c_str());
     //     // printf("2 %s %s\n", V1.at(currentNode->index).c_str(), currentNode->val);
     // }

     for (int i = 0; i < CHAR_NUM; i++) {
         if (currentNode->tireChildNode[i]) {
             getShortsetPrefix(currentNode->tireChildNode[i]);
         }
     }
 }

 void printRes(vector<stringInfo> V) {
     if (!V.size()) {
         cout<<endl;
         // printf("\n");
     }
     vector<stringInfo>::iterator it = V.begin();

     for (;it != V.end(); it++) {
         if (it->abbv.empty()) {
             cout<<it->orginal<<" "<<it->orginal<<endl;
         } else {
             cout<<it->orginal<<" "<<it->abbv<<endl;
             // printf("%s %s\n", it->orginal.c_str(), it->abbv.c_str());
         }
     }

 }

 int main() {
         char word[22] = {0};
         tireTreeHead = NULL;
         V1.clear();
         while(scanf("%s", word) != EOF) {
             // if (!strcmp(word, "end")) {
             //     break;
             // }
             V1.push_back(stringInfo(word));
             buildTireTree(word, V1.size()-1);
         }
         getShortsetPrefix(tireTreeHead);
         printRes(V1);
         return 0;
 }

G++ 1224K 47MS

tire树系列题, 这次用的是动态tire树,静态应该更快,这次也让我意识到,tire树建树本身不是题考察的重点,而是在建立好tire树以后,

如何用这棵树得到最后想要的结果。

题意是得到能无疑义表示该单词的缩写, 想了好久,不知道该如何表示这种abbv,

后来才想明白:

tire树其实是一条条字符串 顺序字符分解 所经过的路径的组合, 那么如何唯一的标示一个字符串? 2种case:

case1: 单词的整个路径都被其他的单词路过,及该单词必是其他单词的前缀,那么唯一表示办法abbv就是单词本身。

case2:  单词在某个字符以后所经过的路径没有被其他单词所经过过,那么唯一标示此单词的abbv就是前面的共享的前缀将上自己独有路径的第一个字符即可.

自己对tire树还是理解不够深入,从路径角度思考,就好理解很多。

那么在有了上面这个条件以后,就好办了, 只需为每个tire node加上一个byTime 来记录有多少个字符串经过此处,

然后在后面遍历此tire数时,察看当前node的byTime是否为1即可,如果是1,那么必定是某个字符串的独有路径,此node所记录的累加字符串即为该字符串的最短abbv,

并且直接return(这条路已经不需要再check了,可以理解为剪枝),遍历其他的tirenode。

本题比较烦人的是最后的输出,

还要按照原来的顺序输出原字符串与abbv, 及不但要得到abbv,还要能记录该abbv是对应于哪个原字符串。

我搞了一个很麻烦的法子,在原字符串输入时,就俺顺序为其分配相应的index,同时在建立tire树的时候,当有新路径被开辟时,tirenode中的index值会设置为此原字符串的index,这样就建立了起来映射关系,

而为了那些整个路径都被共享的原字符串(不能依靠byTime来区分),index在这种情况下也不能用,因为此公共路径的index在输入的时候会被改写多次。

因此就搞了一个复杂的class,存储orginal和addv, addv默认为空, 而original只有在上面遇到独有路径时才会根据node的index来设置vector中的相应的addv。

这样,最后遍历的时候,如果遇到abbv为空的情况,直接输出orginal orginal即可。

一开始WA了几次,原因是设置node的index的时候给了当前node,其实应该设给新建出来的node。

还要找找更好的办法,这个法子太ugly了.

#include <stdio.h>
 #include <string.h>
 #include <vector>
 #include <string>
 #include <cstdlib>
 #include <iostream>

 using namespace std;

 const int CHAR_NUM = 26;

 struct tireNode{
     char val[22];
     struct tireNode * tireChildNode[CHAR_NUM];
     int appearTime;
     int byTime;
     int childNum;
 };

 typedef struct stringInfo stringInfo;
 typedef struct tireNode tireNode;

 vector<string> V1;

 tireNode * tireTreeHead;

 void buildTireTree(char * word) {
     if (!tireTreeHead) {
         tireTreeHead = (tireNode *)malloc(sizeof(tireNode));
         memset(tireTreeHead, 0, sizeof(tireNode));
     }
     int wordLength = strlen(word);

     tireNode * currentNode = tireTreeHead;

     for (int i = 0; i < wordLength; i++) {
         if (!currentNode->tireChildNode[word[i]-'a']) {
             currentNode->tireChildNode[word[i]-'a'] = (tireNode *)malloc(sizeof(tireNode));
             memset(currentNode->tireChildNode[word[i]-'a'], 0, sizeof(tireNode));
             strcpy(currentNode->tireChildNode[word[i]-'a']->val, currentNode->val);
             currentNode->childNum++;
             currentNode->tireChildNode[word[i]-'a']->val[strlen(currentNode->val)] = word[i];
         }
         currentNode = currentNode->tireChildNode[word[i]-'a'];
         (currentNode->byTime)++;
     }
     (currentNode->appearTime)++;
 }

 void getShortsetPrefix(string word) {
     tireNode * currentNode = tireTreeHead;
     int wordLength = word.size();
     for (int i = 0; i < wordLength; i++) {
         if (currentNode->byTime == 1) {
             cout<<word<<" "<<currentNode->val<<endl;
             return;
         } else {
             if (currentNode->tireChildNode[word[i]-'a']) {
                 currentNode = currentNode->tireChildNode[word[i]-'a'];
             }
         }
     }
     cout<<word<<" "<<word<<endl;
 }

 void printRes(vector<string> V) {
     if (!V.size()) {
         cout<<endl;
     }
     vector<string>::iterator it = V.begin();

     for (;it != V.end(); it++) {
         getShortsetPrefix(*it);
     }

 }

 int main() {
         char word[22] = {0};
         tireTreeHead = NULL;
         V1.clear();
         while(scanf("%s", word) != EOF) {
             // if (!strcmp(word, "end")) {
             //     break;
             // }
             V1.push_back(word);
             buildTireTree(word);
         }
         printRes(V1);
         return 0;
 }

G++ 47ms

果然是我SB了,把问题复杂化了。。。

在用vector记录了输入的字符串以后,在输出的时候,只需遍历此vector,

用vector中保存的orginal 字符串对tire数组进行处理即可:

顺序遍历original的字符, 根据字符值沿着tire树中保存的路径一直向下走,沿路检查每个经过node的byTime,如果遇到=1的就输出此orginal abbv return。

否则,如果遍历完都找不到byTime == 1的node,那么可以就直接输出orginal original。

举报

相关推荐

0 条评论