Brevity is Soul of Wit 二分图匹配 将n个字符串缩短(slen<=4且是subsequ,缩短后字符串不能相同)

As we communicate, we learn much new information. However, the process of communication takes too much time. It becomes clear if we look at the words we use in our everyday speech.

We can list many simple words consisting of many letters: "information", "technologies", "university", "construction", "conservatoire", "refrigerator", "stopwatch", "windowsill", "electricity", "government" and so on. Of course, we can continue listing those words ad infinitum.

Fortunately, the solution for that problem has been found. To make our speech clear and brief, we should replace the initial words with those that resemble them but are much shorter. This idea hasn't been brought into life yet, that's why you are chosen to improve the situation.

Let's consider the following formal model of transforming words: we shall assume that one can use n words in a chat. For each words we shall introduce a notion of its shorter variant. We shall define shorter variant of an arbitrary word s as such word t, that meets the following conditions:

  • it occurs in s as a subsequence,
  • its length ranges from one to four characters.

In other words, the word t consists at least of one and at most of four characters that occur in the same order in the word s. Note that those characters do not necessarily follow in s immediately one after another. You are allowed not to shorten the initial word if its length does not exceed four characters.

You are given a list of n different words. Your task is to find a set of their shortened variants. The shortened variants of all words from the list should be different.

Input

The first line of the input file contains the only integer n (1 ≤ n ≤ 200). Then n lines contain a set of different non-empty words that consist of lowercase Latin letters. The length of each word does not exceed 10 characters.

Output

If the solution exists, print in the output file exactly n lines, where the i-th line represents the shortened variant of the i-th word from the initial set. If there are several variants to solve the problem, print any of them. If there is no solution, print -1.

Sample test(s)
input
6
privet
spasibo
codeforces
java
marmelad
normalno
output
pret
sps
cdfs
java
mama
norm
input
5
aaa
aa
a
aaaa
aaaaa
output
-1

//将字符串分解成多个子串,hash+二分图匹配


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=400000;
struct Trie
{
    int idx;
    Trie* next[26];
};
Trie* root;
Trie temp[maxn];
int tp,index;
void reset(Trie* p)
{
    p->idx=-1;
    for(int i=0;i<26;i++) p->next[i]=NULL;
}
void init()
{
    tp=0;
    root=&temp[tp++];
    reset(root);
}
char str[maxn][5];
int insert(char *word)
{
    Trie* p=root;
    for(int i=0;word[i];i++)
    {
        int x=word[i]-'a';
        if(p->next[x]==NULL)
        {
            p->next[x]=&temp[tp++];
            reset(p->next[x]);
        }
        p=p->next[x];
    }
    if(p->idx==-1)
    {
        strcpy(str[++index],word);
        p->idx=index;
    }
    return p->idx;
}




const int N=400000;
/*初始化


注意 加边时候X和Y统一标号,不是分别标号


加边时按照总点数来加
cnt=0;
memset(head,-1,sizeof(head));
*/
int n;//X点数
int link[N];
int sa[N];
bool used[N];
int head[N],cnt;
struct TT
{
    int v,next;
}edge[N];
void addedge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
bool can(int t)
{
    for(int p=head[t];p!=-1;p=edge[p].next)
    {
        int v=edge[p].v;
        if(used[v]==false)
        {
            used[v]=1;
            if(link[v]==-1||can(link[v]))
            {
                link[v]=t;sa[t]=v;
                return true;
            }
        }
    }
    return false;
}
int MaxMatch()
{
    int num=0;
    memset(link,-1,sizeof(link));
    for(int i=1;i<=n;i++)
    {
        memset(used,false,sizeof(used));
        if(can(i)) num++;
    }
    return num;
}




char ch[5];
void dfs(char *s,int u,int len,int limt,int id,int now)
{
    if(now==limt)
    {
        ch[limt]='\0';
        int t=insert(ch);
        addedge(u,t);
        return ;
    }
    if(id==len) return ;
    ch[now]=s[id];
    dfs(s,u,len,limt,id+1,now+1);
    dfs(s,u,len,limt,id+1,now);
}
int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    while(scanf("%d",&n)==1)
    {
        init();
        cnt=0;
        memset(head,-1,sizeof(head));
        index=n;
        for(int i=1;i<=n;i++)
        {
            char s[13];scanf("%s",s);
            int len=strlen(s);
            if(len<=4)
            {
                int t=insert(s);
                addedge(i,t);
            }
            else
            {
                dfs(s,i,len,1,0,0);
                dfs(s,i,len,2,0,0);
                dfs(s,i,len,3,0,0);
                dfs(s,i,len,4,0,0);
            }
        }
        int ans=MaxMatch();
        if(ans==n)
        {
            for(int i=1;i<=n;i++)
            {
                printf("%s\n",str[sa[i]]);
            }
        }
        else
        {
            printf("-1\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值