贪心:字典树openjudge1799-最短前缀

描述

一个字符串的前缀是从该字符串的第一个字符起始的一个子串。例如 "carbon"的字串是: "c", "ca", "car", "carb", "carbo", 和 "carbon"。注意到这里我们不认为空串是字串, 但是每个非空串是它自身的字串. 我们现在希望能用前缀来缩略的表示单词。例如, "carbohydrate" 通常用"carb"来缩略表示. 现在给你一组单词, 要求你找到唯一标识每个单词的最短前缀
在下面的例子中,"carbohydrate" 能被缩略成"carboh", 但是不能被缩略成"carbo" (或其余更短的前缀) 因为已经有一个单词用"carbo"开始
一个精确匹配会覆盖一个前缀匹配,例如,前缀"car"精确匹配单词"car". 因此 "car" 是 "car"的缩略语是没有二义性的 , “car”不会被当成"carriage"或者任何在列表中以"car"开始的单词.
输入输入包括至少2行,至多1000行. 每行包括一个以小写字母组成的单词,单词长度至少是1,至多是20.输出输出的行数与输入的行数相同。每行输出由相应行输入的单词开始,后面跟着一个空格接下来是相应单词的没有二义性的最短前缀标识符。

样例输入

carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate

样例输出

carbohydrate carboh
cart cart
carburetor carbu
caramel cara
caribou cari
carbonic carboni
cartilage carti
carbon carbon
carriage carr
carton carto
car car
carbonate carbona贪心考虑先按字典序排序,然后逐个将单词与前后的作比较,直到找到所求最短前缀。先贴代码
#include<bits/stdc++.h>
using namespace std;
struct mode{
    char w[30],z[30];
    int num;
}a[1010];
bool cmp1(mode x,mode y){
    int i,lx=strlen(x.w),ly=strlen(y.w);
    for( i = 0 ; i <lx&& i<ly ; ++i){
        if(x.w[i]!=y.w[i])return x.w[i]<y.w[i];
    }
    return lx<ly;
}
bool cmp2(mode x,mode y){
    return x.num<y.num;
}
int main(){
    int i = 1,j;
    while((scanf("%s",a[i].w))!=EOF){
        a[i].num=i;
        ++i;
    }
    int sum=i-1;
    sort(a+1,a+sum+1,cmp1);
    for( i = 1 ; i <= sum ; ++i){
        bool flag1=true;
        bool flag2=true;
        int l=strlen(a[i].w);
        for( j = 0 ; j < l ; ++j){
            if(a[i].w[j]!=a[i-1].w[j]){
                flag1=false;
            }
            if(a[i].w[j]!=a[i+1].w[j]){
                flag2=false;
            }
            if(!flag1&&!flag2)break;
        }
        if(j==l)--j;
        for(int k = 0 ; k <= j ; ++k )a[i].z[k]=a[i].w[k];
    }
    sort(a+1,a+sum+1,cmp2);
    for(int i = 1 ; i <= sum ; ++i){
        printf("%s %s\n",a[i].w,a[i].z);
    }
    return 0;
}

需要注意的是,在比较前与后时不能用如下判断:

for( i = 1 ; i <= sum ; ++i){
        int l=strlen(a[i].w);
        for( j = 0 ; j < l ; ++j){
            if(a[i].w[j]!=a[i-1].w[j]&&a[i].w[j]!=a[i+1].w[j]){
                break;
            }
        }

比如:

abct

abcxt

abext

第二个的最短为abcx,若用如上方法判断会得到abcxt。

所以需要开两个flag,当上下两个都为false时,就找到了前缀的尾。(特别鸣谢马哥出了这个数据,毕竟自己调了好久也没发现这个错误QAQ)

就是这样了。

时间: 2024-10-13 08:35:21

贪心:字典树openjudge1799-最短前缀的相关文章

P4551 最长异或路径 (01字典树,异或前缀和)

题目描述 给定一棵 nn 个点的带权树,结点下标从 11 开始到 NN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式: 第一行一个整数 NN ,表示点数. 接下来 n-1n?1 行,给出 u,v,wu,v,w ,分别表示树上的 uu 点和 vv 点有连边,边的权值是 ww . 输出格式: 一行,一个整数表示答案. 输入输出样例 输入样例#1: 4 1 2 3 2 3 4 2 4 6 输出样例#1: 7 说明 最长异或序

字典树(数组 查找前缀)

int trie[400001][26],len,root,tot,sum[400001]; bool p; int n,m; char s[11]; void insert() { len=strlen(s); root=0; for(int i=0;i<len;i++) { int id=s[i]-'a'; if(!trie[root][id]) trie[root][id]=++tot; sum[trie[root][id]]++;//前缀后移一个位置保存 root=trie[root][

Ancient Printer HDU - 3460 贪心+字典树

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

trie树(字典树)

1. trie树,又名字典树,顾名思义,它是可以用来作字符串查找的数据结构,它的查找效率比散列表还要高. trie树的建树: 比如有字符串"ab" ,"adb","adc"   可以建立字典树如图: 树的根节点head不存储信息,它有26个next指针,分别对应着字符a,b,c等.插入字符串ab时,next['a'-'a']即next[0]为空,这是申请一个结点放在next[0]的位置,插入字符串db时,next['d'-'a']即next[3]

UVALive 5913 字典树

先输入n个字符串的字典,每个字符串的前缀+后缀可以组成新的合法字符串,但肯定是有重复的,问从给定的字符串,生成的所有可能的字符串为多少个 把前缀和后缀压入字典树,达到前缀和后缀的去重,首先的总和即为前缀数目乘以后缀数目,之后为了去重,记录每个前后缀非第一个相同的每个字母,则每个相同字母必定会产生重复.减掉即可..还要注意,len=1的字符串特判..注意细节处理 #include <iostream> #include <cstdio> #include <cstring>

Barty&#39;s Computer 字典树

https://nanti.jisuanke.com/t/17122 Barty have a computer, it can do these two things. Add a new string to its memory, the length of this string is even. For given 44 strings a,b,c,da,b,c,d, find out how many strings that can be product by a+s1+b+c+s2

字典树的实现

 字典树常用于前缀匹配 [[email protected] 0813]$ cat dic_tree.cpp #include <iostream> #include <stdio.h> #define MAX 26 usingnamespace std; typedefstruct TrieNode { intncount; structTrieNode *next[MAX]; }TrieNode; voidinit(TrieNode **pRoot)//初始化 { *pRo

hdu 4760 Good Firewall(字典树)

题目链接:hdu 4760 Good Firewall 题目大意:有一个防火墙,具有添加一个子网络,删除一个子网络,以及转发包的操作. 添加操作包含子网络的id,以及子网络的子网掩码(计算出网络前缀,以及ip的下限),不会超过15个. 删除则是给定要删除的子网络id. 转发操作,给定两个ip,如果两个ip在同一个子网络中,则可以转发,否则丢弃. 解题思路:对子网掩码前缀建立字典树,每个前缀终止节点用一个set记录属于哪些子网络,ip下限.那么增加和删除操 作既可以解决了.对于查询操作,分别查询两

[BZOJ1590] [Usaco2008 Dec]Secret Message 秘密信息(字典树)

传送门 看到前缀就要想到字典树! 看到前缀就要想到字典树! 看到前缀就要想到字典树! #include <cstdio> #include <iostream> #define N 500001 int n, m, k, cnt; int a[N], val[N], num[N], next[N][2]; inline int read() { int x = 0, f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getch