链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3460
题目:
2 freeradiant freeopen
21HintThe 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 (转载请标明)