• hdu3460 Ancient Printer


    唉,又这样贡献了一个WA,忘了把自己的用来测试的输出删了……

    一开始还真被这题目吓住了,不过花点心思想想,还是可以做出来的

    题意要求的是打印单词的最少操作数

    只有三个操作:

    输入,删除,还有打印,前缀就不需要重复输入,想到了字典树,这道题目也就好做了

    要 求最少的操作数,所以首先要归类,所有拥有相同前缀的单词,放在一块输入,题目还说,最后一次打印不需要删除

    理论上是像上面说的,但实际我们在计算最少操作数时,可以这样算,首先假设所有的单词都需要重新打印还有删除,所以总操作数是单词总长度*2

    接下来,计算出前缀,可以这样想,只需计算出每一个节点被哪些单词共有,如题目中的样例,“freeradiant”,“freeopen”,f 被俩个节点共有,所以省了一步删除还有一步输入,所以就是(2-1)*2;

    最后再找 出最长的一个单词的长度max,很容易理解,最后一行不用删除,那最后一行肯定是越长越好,

    根据这三个数值,可以发现,最少的操作=总操作数-总共可以省掉的操作数-多删除掉的最后一行的长度(max)

    在代码实现上,额,125ms,不是很快,还是用到了栈还有字典树

    更具体的解释,看代码吧

    #include<iostream>
    #include<stack>
    #include<string>
    using namespace std;
    struct node
    {
    	node *next[26];
    	int v;//记录有多少个单词经过该节点,或者说,有多少单词拥有到该节点为止的前缀
    	int lev;//层数,好像用处不是很大
    };
    node *root;
    void insert(char *s)//插入操作
    {
    	node *p=root;
    	for(;*s!='\0';s++)
    	{
    		int d=*s-'a';
    		if(p->next[d]!=NULL)
    		{
    			p=p->next[d];
    			p->v++;
    		}
    		else 
    		{
    			p->next[d]=new node();
    			p=p->next[d];	
    			p->v++;
    		}
    	}
    }
    int find()//遍历整棵树
    {
    	node *p=root,*cur=root,*nex;
    	int sum=0;
    	stack<node*> nd;
    	cur->lev=0;
    	nd.push(cur);
    	while(!nd.empty())
    	{
    		cur=nd.top();
    		nd.pop();
    		if(cur->lev>0)//根节点不计算
    		{
    		  sum+=(cur->v-1)*2;
    		}
    		for(int i=0;i<26;i++)
    		{
    			nex=cur->next[i];
    			if(nex!=NULL&&nex->v>1)//单词数大于一,表示有可以省掉的操作,才有必要进行计算,
    			{
    				nex->lev=cur->lev+1;
    				nd.push(nex);//压入栈
    			}
    		}
    	}
    	return sum;
    }
    void del(node *p)//释放空间
    {
    	for(int i=0;i<26;i++)
    	{
    		if(p->next[i]!=NULL)
    			del(p->next[i]);
    	}
    	delete(p);
    }
    int main()
    {
    	int sum,i,j,n,max,len;
    	char str[55];
    	while(scanf("%d",&n)!=EOF)
    	{
    		sum=max=0;
    		root=new node();
    		for(i=0;i<n;i++)
    		{
    			scanf("%s",str);
    			insert(str);
    			len=strlen(str);
    			if(len>max)//找出最长的单词
    				max=len;
    			sum+=len;//计算单词总长度
    		}
    		j=find();
    		sum=sum*2-j-max+n;
    		cout<<sum<<endl;
    		del(root);
    	}
    }
    
  • 相关阅读:
    [bzoj3527][Zjoi2014]力_FFT
    [bzoj2194]快速傅立叶之二_FFT
    [bzoj2179]FFT快速傅立叶_FFT
    [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
    [bzoj3436]小K的农场_差分约束
    [bzoj3712][PA2014]Fiolki_倍增LCA
    [bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd
    [bzoj2150]部落战争_二分图最小路径覆盖
    [bzoj1059][ZJOI2007]矩阵游戏_二分图最大匹配
    python_SMTP and POP3
  • 原文地址:https://www.cnblogs.com/nanke/p/2046998.html
Copyright © 2020-2023  润新知