最优无分隔符字典问题

问题描述

设∑=(α1,α2,…,αn)是 n 个互不相同的符号组成的符号集。
Lk={β1β2…βk|βi∈∑,1≤i≤k}是∑中字符组成的长度为k的全体字符串。 S⊆Lk是Lk的1个无分隔符字典是指对任意a1a2…ak∈Sa1a2…ak∈S和b1…bk∈S则
{a2a3…akb1,a3a4…b1b2,…,akb1b2…bk−1}⋂S=∅
无分隔符字典问题要求对给定的 n, ∑以及正整数 k,编程计算 Lk 的最大无分隔符字典。

设计一个算法,对于给定的正整数 n 和 k,编程计算 Lk的最大无分隔符字典。

数据输入:
第一行有 2 个正整数 n 和 k。

代码展示

package algorithm;

import java.util.*;

public class WuFenGeFuZiDian {

    private static int n, k;
    private static int[] ak;
    private static int lk;
    private static int[] x;
    private static int best;

    private static int MAX = 10000;
    private static Set<Integer> S;
    private static Set<Integer> res;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while (true) {
            best = 0;

            n = input.nextInt();
            k = input.nextInt();

            S = new HashSet<>(MAX);
            res = new HashSet<>(MAX);
            ak = new int[2*k];
            x = new int[n+1];
            lk = n;

            for (int i=1; i<=n; i++)
                x[i] = i;

            for (int i=1; i<k; i++)
                lk *= n;
            lk--;

            search(0);

            System.out.println("当前最大无分隔符字典元素数量为:");

            System.out.println(best);
            System.out.println("最大字典集合:"+res);
        }
    }
    
    //ii是a1a2...akb1b2...bk-1的bi的下标。i-1是bi为结尾的字符串开始的位置。
    private static int digi(int i) {
        int ii = k+i-2;
        int x = ak[i-1];
        for (int j=0; j<k-1; j++) {
            x *= n;
            x += ak[i];
            i++;
        }
        return x;
    }

    //判断字符串a和b是否互不为前缀
    private static boolean pref(int a, int b) {
        int x = a;
        int y = b/n;
        for (int i=0; i<k-1; i++){
            ak[k-i-2] = x%n;
            x /= n;
            ak[2*k-i-3] = y%n;
            y /= n;
        }
        for (int i=1; i<k; i++)
            if (S.contains(digi(i)))
                return true;

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

        return false;
    }

    private static boolean oka(int b) {
        S.add(b);
        for (Integer a : S) {
            if (a != b && pref(a, b)) {
                S.remove(b);
                return false;
            }
        }

        return true;
    }

    //逐步加深的回溯法
    private static void search(int dep) {
        if (dep > lk) {
            if (S.size() > best) {
                best = S.size();
                res.clear();
                res.addAll(S);
            }
            return;
        }
        if (oka(dep)) {
            S.add(dep);
            search(dep + 1);
            S.remove(dep);
        }
        search(dep + 1);
    }
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值