无分隔符字典问题

#include <iostream>
#include <fstream>
#include <vector>
#include <set>
using namespace std;

int *ak;
int lk;
int n, k; 
int best = 0; //最大无分隔符字典元素个数

vector<int> L;  //将所有的长度为k的数字字符串存到集合L中
set<int> S;  //当前字典中的字符串存储在集合s中


//将下标为L[]中下标为i的字符串存入集合s
void insert(int i)
{
    S.insert(L[i]);
}

//将下标为L[]中下标为i的字符串存入集合s
void erase(int i)
{
    S.erase(L[i]);
}

//将ak[]中起点为i-1,长度为k-1数字串转换为十进制数字
int digi(int i)
{
    int ii = k + i - 2;
    int x = ak[ii--];
    for(int j=0; j<k-1; j++)
    {
        x *= 10;
        x += ak[ii];
        ii--;
    }
    return x;
}

//判断字符串a和第b个字符串是否互不为前缀
bool pref(int a, int b)
{
    int bb = L[b];
    int x = a;
    int y = bb/n;  //去掉最高位,得到低k-1位
    for(int i=0; i<k-1; i++) //ak[0, k-2]存放x的低k-1位,ak[k-1, k-1 + (k-2)]存放y
    {
        ak[k-i-2] = x % n;
        x /= n;
        ak[2*k-i-3] = y % n;
        y /= n;
    }
    for(i=1; i<k; i++) //相当于依次判断a2a3..akb1, a3a4..b1b2, akb1..bk-1是否已存在于S中,本程序中下标从0开始
        if(S.count(digi(i)) > 0)  //如果已存在于S中
            return true;

    x = bb;
    y = a/n;
    for(i=0; i<k-1; i++)
    {
        ak[k-i-2] = x % n;
        x /= n;
        ak[2*k-i-3] = y % n;
        y /= n;
    }
    for(i=1; i<k; i++)
        if(S.count(digi(i)) > 0)
            return true;

    return false;
}

//判断当前下标为b的字符串是否可以加入字典
//将字符串a1a2..ak看作k位十进制数
bool oka(int b)
{
    int bb = L[b];
    set<int>::iterator it;  //定义迭代器
    it = S.begin();
    while(it != S.end())
    {
        int a = *it;
        if(pref(a, bb)) //如果a,b其中一个是另一个的前缀
            return false;
        it++;
    }
    return true;
}

//得到总元素个数为n,长度为m的全排列
void Perm(int list[], int dep, int m, int n)  
{  
    if(dep>m)  
    {  
        int x = 0;
        for(int i=1; i<=m; i++)  
            x = x*10 + list[i];   //转换为十进制数字
        L.push_back(x);  //将所有的数字字符串存到集合L中

    }  
    else  
        for(int j=1;j<=n;j++)  
        {  
            swap(list[dep], list[j]);  
            Perm(list, dep+1, m,  n);  
            swap(list[dep], list[j]);  
        }  
} 


void backtrack(int dep)
{
    if(dep >= lk)
    {
        if(S.size() > best)
            best = S.size();
        return;
    }
    if(oka(dep))
    {
        insert(dep);
        backtrack(dep+1);
        erase(dep);
    }
    backtrack(dep+1);
}


int main()
{
    ifstream fin("无分隔符字典.txt");
    cout << "输入正整数n:";
    fin >> n; cout << n;
    cout << "\n输入正整数k:";
    fin >> k; cout << k;
    ak = new int[2*k];
    lk = n;
    for(int i=1; i<k; i++) //k个字符中,每一个字符都有n种选择,n^k表示所有由k个字符组成的字符串种数
        lk *= n;
    lk--;

    int *x = new int[n+1];
    for(i=1; i<=n; i++)
        x[i] = i;
    Perm(x, 1, k, n); //将长度为k的全排列存入集合L中
    backtrack(0);
    cout << "\n最大无分隔符字典元素个数为:" << best;

    cout << endl;
    cout << endl;
    fin.close();
    return 0;
}

这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值