http://acm.hdu.edu.cn/showproblem.php?pid=3460
题意:有一台打印机,它只能每次输入一个单词并打印,输入下一个单词时,必须把第一个单词删掉(但如果两个单词有相同的前缀,只需删除不同的部分即可),计算打印机最少所需的操作次数。
分析:注意最后一个单词可以不删除,我的想法是相同单词的前缀只用打印、删除一次,其余部分*2(如:三个单词aB、aC、aD,a是前缀,那么ans=2*a+2*B+2*C+2*D+n-mlen,mlen=max(len))
也可以得出公式:ans=所有节点(除头结点外)个数*2 + 字符串个数 - 最长的字符串长度(mlen)。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=10005;
char str[NM][55];
int mmax,ans;
struct Node{
Node *next[26];
int cc;
Node(){
for(int i=0;i<26;i++)
next[i]=NULL;
cc=0;
}
};
void BuildT(Node *tree,char *s1)
{
int i,len,t;
len=strlen(s1);
for(i=0;i<len;i++)
{
t=s1[i]-'a';
if(tree->next[t]==NULL)
tree->next[t]=new Node();
tree=tree->next[t];
tree->cc++;
}
}
void SearchT(Node *tree,char *s1)
{
int i,len,t;
len=strlen(s1);
if(mmax<len) mmax=len; //
for(i=0;i<len;i++)
{
t=s1[i]-'a';
tree=tree->next[t];
if(tree->cc>1) //计算 前缀 所需次数
{
if(tree->cc>1){
ans+=2;
tree->cc=-1;
}
}
else if(tree->cc==1) //计算 其余部分 所需次数
{
int temp=len-i;
ans+=(temp)*2;
break;
}
}
}
void DelT(Node *tree)
{
for(int i=0;i<26;i++)
if(tree->next[i]!=NULL)
DelT(tree->next[i]);
delete tree;
}
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF)
{
Node *p=new Node();
for(i=0;i<n;i++)
{
scanf("%s",str[i]);
BuildT(p,str[i]);
}
ans=mmax=0;
for(i=0;i<n;i++)
SearchT(p,str[i]);
printf("%d\n",ans-mmax+n);
DelT(p);
}
return 0;
}