zoukankan      html  css  js  c++  java
  • Luogu P4683【IOI2008】Type Printer 打印机|trie

    【IOI2008】Type Printer 打印机|trie

    链接

    题意:一个打印机,支持向其加减一个字母和打印的操作。给出(N)个单词,求打印这些单词的最小操作数。注意,打印结束后允许打印机内有字母,且打印次序任意。

    (1le N le 25000),单词均小写,最大长度20

    分析:由于打印操作是无法省去的,操作数最小就要在加减字母下功夫。显然若两单词有相同前缀,则可以通过共用前缀的方式解决。这样可减少一次加减共两个操作。

    同时,由于最后一个单词打印后可不删除,因此最后一个单词要尽量长

    根据相同前缀这一条件,我们联想到结构与此一致的trie,故使用Trie维护单词。

    可以证明,本题答案就是trie上节点个数*2(加,减各一次)+单词数-最长单词长度(省略‘-’)。

    那么接下来就是打印方案了,这里采用将最后打印的单词的节点最后遍历,其他的先遍历(显然不影响答案)的方法,在进入节点时输出字母,退出时输出-,同时若该节点有单词的结束标记时打印P即可解决。

    上代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,len,num,maxl,maxn,g,ans;string st[30000];
    struct trie
    {
    	int L[26];int e;
    }tree[901000];
    void addtrie(int x,int y)
    {
    	if (y==len) 
    	{
    		tree[x].e=true;
    		return ;
    	}
    	int ne=st[num][y]-'a';
    	if (!tree[x].L[ne])
    	{
    		g++;
    		tree[x].L[ne]=g;
    	}
    	addtrie(tree[x].L[ne],y+1);
    }
    void printrie(int x,int y,bool o)
    {
    	int ne=0;
    	if (!o) ne=26; else ne=st[maxn][y]-'a';
    	if (tree[x].e) cout<<"P
    ";
    	for (int i=0;i<26;i++)
    	{
    		if (i==ne) continue;
    		if (tree[x].L[i])//有就遍历
    		{
    			cout<<char(i+'a')<<endl;
    			printrie(tree[x].L[i],y+1,0);
    			cout<<"-
    ";
    		}
    	}
    	if (o&&y!=maxl)//最后遍历最长单词
    	{
    		cout<<char(ne+'a')<<endl;
    		printrie(tree[x].L[ne],y+1,1);
    	}
    }
    int main()
    {
    	cin>>n;
    	for (int i=1;i<=n;i++)
    	{
    		cin>>st[i];
    		num=i;len=st[i].size();
    		if (maxl<len)
    		{
    			maxl=max(maxl,len);
    			maxn=i;
    		}
    		addtrie(0,0);//建trie
    	}
    	ans=g*2+n-maxl;
    	cout<<ans<<endl;
    	printrie(0,0,1);
    	return 0;
    }
    

    广告Trie学习笔记

  • 相关阅读:
    程序是怎样跑起来的 第三章
    C#4.5-4.7学习总结
    第二周学习总结
    程序是如何跑起来的 第二章
    第一章读后感
    师生关系读后感
    C#学习总结
    我与计算机
    读《程序怎样跑起来》第一章有感
    读师生关系有感
  • 原文地址:https://www.cnblogs.com/fmj123/p/13460225.html
Copyright © 2011-2022 走看看