题解 | #素数伴侣#

素数伴侣

https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e

这题我是硬想出来的,感觉原理挺简单的,重点在把题目的模型抽象出来。

我们可以把题目理解为:

给你一张无向图,每找出一条边就删除这条边以及它的两个端点,让你找出最多的边。

那这就简单了。我来说说我的思路:

准备工作

首先是准备工作。因为输入的数字在2到30000之间,所以两数相加的和最多在4到60000之间。准备一个容器来存储这些素数,一会直接用contains方法找就行。

具体方法就不写了,有个小技巧就是如果除数遍历到了这个数的(int)平方根了,还不能整除,那这个被除数肯定是素数,直接省一半时间复杂度。

构建模型

然后就要开始建模了,这里基于贪心策略,所以建议所有容器使用红黑树作为底层。

1).先把每个输入的数做成一个结点,包含数的值和它的子结点集合children。子节点的含义就是和它成对的结点们。用来表示图中的边。

2).再做一个容器set,用来表示整个图中的所有结点,方便后面遍历。

3).遍历,把每个结点的子结点集合赋值,如果该结点的子结点集合中有元素,放入容器。

4).从set中挑出子结点最少(连线最少)的那个结点x,再从x的子结点中挑出子结点最少的结点y。从set、children中删除这两个结点。这样就从无向图中删掉了“影响最小”的两个结点。

5)

重复4,直至set中没有结点或set中的结点的children都没有子结点。

以下是代码。感觉用Map做更好些,懒得重构了,大概意思是这样。

import java.util.*;

/**
 * @author FunnelCakes
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //制作素数集合,3到60000全部素数
        Set<Integer> primeSet = new TreeSet<>();
        for (int i = 4; i < 60000; i++) {
            boolean flag = true;
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if (i % j == 0) {
                    flag = false;
                    break;
                }
            }
            if (flag)
                primeSet.add(i);
        }

        while (scanner.hasNext()) {
            //读入
            int n = scanner.nextInt();//第一行,n
            int[] vals = new int[n];//第二行,n个正整数
            for (int i = 0; i < n; i++) {
                vals[i] = scanner.nextInt();
            }
            List<PointNode> pointNodeList = new ArrayList<>();
            for (int val : vals) {
                pointNodeList.add(new PointNode(val));
            }
            //结点匹配,构建无向图
            PointNodeSet pointNodeSet = new PointNodeSet(new PointNodeComparator());
            for (PointNode pointNode : pointNodeList) {
                for (PointNode pointNode1 : pointNodeList) {
                    if (pointNode.val != pointNode1.val) {
                        int plus = pointNode.val + pointNode1.val;
                        if (primeSet.contains(plus)) {
                            pointNode.children.add(pointNode1);
                        }
                    }
                }
                if (!pointNode.children.isEmpty()) {
                    pointNodeSet.add(pointNode);
                }
            }
            //成对移除pointNodeSet,删除边
            int count = 0;
            while (!pointNodeSet.isEmpty()) {
                PointNode pointNode1 = pointNodeSet.first();
                if (pointNode1.children.isEmpty()) {
                    pointNodeSet.remove(pointNode1);
                } else {
                    PointNode pointNode2 = pointNode1.children.first();
                    pointNodeSet.removeSide(pointNode1, pointNode2);
                    count++;
                }
            }

            System.out.println(count);
            break;
        }
    }
}

//以下是模型,写得稀碎,别骂了别骂了。。
class PointNodeSet extends TreeSet<PointNode> {
    private static PointNodeComparator pointNodeComparator;

    public PointNodeSet(Comparator<? super PointNode> comparator) {
        super(comparator);
    }

    @Override
    public Comparator<? super PointNode> comparator() {
        return new PointNodeComparator();
    }

    //删除边
    public boolean removeSide(PointNode o1, PointNode o2) {

        if (o1 == null || o2 == null)
            return false;
        /*System.out.println(this.remove(o1));
        System.out.println(this.remove(o2));*/
        PointNodeSet tmpSet = new PointNodeSet(new PointNodeComparator());

        for (PointNode pointNode : this) {
            if (!pointNode.equals(o1) && !pointNode.equals(o2)) {
                pointNode.children.remove(o1);
                pointNode.children.remove(o2);
                tmpSet.add(pointNode);
            }
        }
        this.clear();
        this.addAll(tmpSet);
        return true;
    }

    @Override
    public boolean remove(Object o) {
        PointNode obj = (PointNode) o;
        if (o == null)
            return false;
        Iterator<PointNode> iterator = this.iterator();
        boolean flag = false;
        while (iterator.hasNext()) {
            if (iterator.next().val == obj.val) {
                flag = true;
                iterator.remove();
                break;
            }
        }
        return flag;

    }
}

class PointNode {
    public int val;
    public PointNodeSet children;

    public PointNode(int val) {
        this.val = val;
        this.children = new PointNodeSet(new PointNodeComparator());
    }


}

class PointNodeComparator implements Comparator<PointNode> {


    @Override
    public int compare(PointNode o1, PointNode o2) {

        if (o1.children.size() == o2.children.size())
            return -1;
        return o1.children.size() - o2.children.size();
    }
}

全部评论

相关推荐

美团 后端开发 总包n(15%是股票)
点赞 评论 收藏
分享
11-11 14:21
西京学院 C++
无敌混子大王:首先一点,不管学校层次怎么样,教育经历放在第一页靠上位置,第一页看不到教育经历,hr基本直接扔掉了
点赞 评论 收藏
分享
斑驳不同:还为啥暴躁 假的不骂你骂谁啊
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务