HDU 3460 Ancient Printer

链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3460


题目:

Ancient Printer

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 955    Accepted Submission(s): 441


Problem Description
The contest is beginning! While preparing the contest, iSea wanted to print the teams' names separately on a single paper.
Unfortunately, what iSea could find was only an ancient printer: so ancient that you can't believe it, it only had three kinds of operations:

● 'a'-'z': twenty-six letters you can type
● 'Del': delete the last letter if it exists
● 'Print': print the word you have typed in the printer

The printer was empty in the beginning, iSea must use the three operations to print all the teams' name, not necessarily in the order in the input. Each time, he can type letters at the end of printer, or delete the last letter, or print the current word. After printing, the letters are stilling in the printer, you may delete some letters to print the next one, but you needn't delete the last word's letters.
iSea wanted to minimize the total number of operations, help him, please.
 

Input
There are several test cases in the input.

Each test case begin with one integer N (1 ≤ N ≤ 10000), indicating the number of team names.
Then N strings follow, each string only contains lowercases, not empty, and its length is no more than 50.

The input terminates by end of file marker.
 

Output
For each test case, output one integer, indicating minimum number of operations.
 

Sample Input
  
  
2 freeradiant freeopen
 

Sample Output
  
  
21
Hint
The sample's operation is: f-r-e-e-o-p-e-n-Print-Del-Del-Del-Del-r-a-d-i-a-n-t-Print
 

分析与总结:

这题是昨晚睡觉前1小时做的,初看时觉得挺水的,直接遍历一遍,根据所走的路径进行计数,回溯时也要计数(如果已经全部打印完了,那么回溯时就不再计数了)。

样例得出来后很开心地提交了,结果WA得一塌糊涂。改了几个地方后还是WA, 然后就先睡觉了。

第二天醒来再想这道题,发现那样计数是不可以的。因为那样子遍历,遍历到的最后一个单词一定是字典序最大的,但是字典序最大的不一定是最短的,应该选择最长的那个单词在最后一次打印,这样子才能节省最短的步数。

所以,直接遍历统计Trie树上的字母个数cnt, 设最长的单词长度为maxLen,那么答案便是 2*cnt+n-maxLen.

cnt要乘2, 是因为打印后还要一个一个删除掉,相当于每个单词走了两次。

加上n, 就是打印的次数。

减去maxLen,是因为最后一个单词不需要删除。



代码:

#include<iostream>
#include<cstdio> 
#include<cstring>
using namespace std;

const int KIND = 26;
const int MAXN = 500000;
int cnt_node;
int cnt;
int n;

struct node{
    bool isword;
    int cnt;
    node* next[KIND];
    void init(){
        cnt=0;
        isword=false;
        memset(next, 0, sizeof(next));
    }
}Heap[MAXN];

inline node* new_node(){
    Heap[cnt_node].init();
    return &Heap[cnt_node++];
}

void insert(node* root, char *str){
    for(char *p=str; *p; ++p){
        int ch=*p-'a';
        if(root->next[ch]==NULL)
            root->next[ch] = new_node();
        root = root->next[ch];
    }
    root->isword = true;
    ++root->cnt;
}
void dfs(node *root){
    for(int v=0; v<26; ++v){
        if(root->next[v]!=NULL){
            ++cnt;
            dfs(root->next[v]);
        }
    }
}

int main(){
    char str[55];
    while(~scanf("%d",&n)){
        cnt_node=0;
        node* root = new_node();
        int Max=0;
        for(int i=0; i<n; ++i){
            scanf("%s",str);
            int len=strlen(str);
            if(len>Max)Max=len;
            insert(root, str);
        }
        cnt=0;
        dfs(root);
        printf("%d\n",cnt*2+n-Max);
    }
    return 0;
}


 ——  生命的意义,在于赋予它意义士。

          原创 http://blog.csdn.net/shuangde800 , By   D_Double  (转载请标明)




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值