hdu3460 字典树(打印机)

题意:
       给你一些名字,让你用一台打印机去打印这些名字,打印机只有三个操作
(1)打印的都是小写字母
(2)每次可以在当前字母的后面加一位,或删除一位。
(3)打印当前串
问你最少多少步可以吧所有的名字都打完。

思路:
      这个题目首先要看懂题目,不然测试数据都模拟不过去,曾加一个字母,删除一个字母,打印,每一种都算是一步,首先我们把所有的字母都建在一棵树里,也就是字典树存下所有的名字,ans =(字典树节点数-1)* 2 + 名字数 - 最长的名字     
下面分步理解这个式子,节点数-1是因为字典树的根节点没有字母,*2是因为假设每一个字母增加上去又删除了,+名字数 是因为每个名字都要输出一下,输出算一步,-最长名字长度,是因为最后一个名字是不用再打印机上删除的,我们选择一个最每一长的这样能达到步骤最少。然后在整体理解下,在一棵树上,每一个节点都是一棵子树的树根,对于每一棵树,他的根节点的字母只要被增加一次删除一次就行了(最后的不用删除)。这样就可以很好的理解答案为什么是

ans = T_n * 2 + n - maxl 了。

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

typedef struct Tree
{
    Tree *next[26];
}Tree;

Tree root;
int sum;

void Buid_Tree(char *str)
{
    int len = strlen(str);
    Tree *p = &root ,*q;
    for(int i = 0 ;i < len ;i ++)
    {
        int id = str[i] - 'a';
        if(p -> next[id] == NULL)
        {
            sum ++;
            q = (Tree *)malloc(sizeof(root));
            for(int j = 0 ;j < 26 ;j ++)
            q -> next[j] = NULL;
            p -> next[id] = q;
        }
        p = p -> next[id];
     }
}

int main ()
{
    int n ,i;
    char str[55];
    while(~scanf("%d" ,&n))
    {
       for(sum = 0 ,i = 0 ;i < 26 ;i ++)
       root.next[i] = NULL;
       int maxl = 0;
       for(i = 1 ;i <= n ;i ++)
       {
          scanf("%s" ,str);
          if(maxl < strlen(str)) maxl = strlen(str);
          Buid_Tree(str);
       }
       printf("%d
" ,sum * 2 + n - maxl);
     }
     return 0;
}

原文地址:https://www.cnblogs.com/csnd/p/12062977.html