算法导论之第四章-习题4-6VLSI芯片测试

package test2018.test08;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
* 题目概要:
* 有n多个设备
* 两两测试
* 如果两个都是好的,测试结果必为好
* 一好一坏必为坏
* 两坏可能好可能为坏
* 用o(n)进行实现
* 本方法
* T(n) = T(n/2) + b;b小于圈数平方,以1千万条为例,小于400;
* 之所以时间大于合并排序,应该是数组的合并比较费时
*
* 用数组比用list要快一点
*
* 解题思路:题目中已经有提示,当好的个数超过一半时,方可进行测试
* 而且好的和好的之间,进行判断肯定为好,好的和坏的肯定为坏,故以好的和好的构建圈,必定能把所有好的围成一个圈
* 然后找到超过半数的那个圈,必定是好圈
*
* @author: guzhangyan
* @date: 2018年8月6日 上午11:35:15
*/

public class Class6VLSI {

    static int sheBeiNum = 10000000;
    static Random random = new Random();

    public static void main(String[] args) {
        long stratTime = System.currentTimeMillis();
        int[] shebei = new int[sheBeiNum];
        for (int i = 0; i < shebei.length; i++) {
            /*
             * if(i<100) { shebei[i] = 1; continue; }
             */// 前100个都不是的情况下,也能成功
            shebei[i] = random.nextInt(19) % 2;// 0代表好设备
        }
        int breakNum = 0;
        for (int i = 0; i < shebei.length; i++) {
            breakNum += shebei[i];
        }
        if (sheBeiNum - breakNum <= sheBeiNum / 2) {
            System.out.println("好的设备太少");
            return;
        }
        // System.out.println(Arrays.toString(shebei));
        System.out.println(findOneGood2(shebei));
        long endTime = System.currentTimeMillis();
        System.out.println("VLSI时间:" + (endTime - stratTime));
    }

    // 可以看成朋友圈问题,在一个圈内,真的之间肯定能成为朋友,到时候,哪个圈大,那个圈就都是真
    // 用list来操作
    private static int findOneGood1(int[] shebei) {
        int start = 0;
        int end = shebei.length - 1;
        List<List<Integer>> pengyouquans = getQuan(shebei, start, end);
        System.out.println(pengyouquans.size());
        for (List<Integer> list : pengyouquans) {
            if (list.size() > sheBeiNum / 2) {
                // System.out.println(list.toString());
                return list.get(0);
            }
        }
        return -1;
    }

    private static List<List<Integer>> getQuan(int[] shebei, int start, int end) {
        if (end == start) {
            List<List<Integer>> pengyouquans = new ArrayList<List<Integer>>();
            List<Integer> lists = new ArrayList<Integer>();
            lists.add(start);
            pengyouquans.add(lists);
            return pengyouquans;
        }
        List<List<Integer>> pengyouquans1 = getQuan(shebei, start, (start + end) / 2);
        List<List<Integer>> pengyouquans2 = getQuan(shebei, (start + end) / 2 + 1, end);
        List<List<Integer>> returnLists = new ArrayList<List<Integer>>();
        for (int i = 0; i < pengyouquans1.size(); i++) {
            for (int j = 0; j < pengyouquans2.size(); j++) {
                if (shebeiPanDuan(shebei, pengyouquans1.get(i).get(0), pengyouquans2.get(j).get(0))) {
                    pengyouquans1.get(i).addAll(pengyouquans2.get(j));
                    pengyouquans2.remove(j);
                    break;
                }
            }
            returnLists.add(pengyouquans1.get(i));
        }
        for (int j = 0; j < pengyouquans2.size(); j++) {
            returnLists.add(pengyouquans2.get(j));
        }
        /*
         * for (List<Integer> list : returnLists) {
         * System.out.println(start+":"+end+"----"+list.toString()); }
         */
        return returnLists;
    }

    // 可以看成朋友圈问题,在一个圈内,真的之间肯定能成为朋友,到时候,哪个圈大,那个圈就都是真
    // 用数组来操作
    private static int findOneGood2(int[] shebei) {
        // System.out.println("start::::findOneGood2");
        int start = 0;
        int end = shebei.length - 1;
        int[][] pengyouquans = getQuan2(shebei, start, end);
        System.out.println(pengyouquans.length);
        for (int i = 0; i < pengyouquans.length; i++) {
            int[] list = pengyouquans[i];
            if (list.length > sheBeiNum / 2) {
                return list[0];
            }
        }
        return -1;
    }

    private static int[][] getQuan2(int[] shebei, int start, int end) {
        if (end == start) {
            int[][] pengyouquans = { { start } };
            return pengyouquans;
        }
        // System.out.println("start::::"+start+":"+end);
        int[][] pengyouquans1 = getQuan2(shebei, start, (start + end) / 2);
        int[][] pengyouquans2 = getQuan2(shebei, (start + end) / 2 + 1, end);
        int[][] returnLists = new int[0][0];
        for (int i = 0; i < pengyouquans1.length; i++) {
            for (int j = 0; j < pengyouquans2.length; j++) {
                if (shebeiPanDuan(shebei, pengyouquans1[i][0], pengyouquans2[j][0])) {
                    pengyouquans1[i] = addAll(pengyouquans1[i], pengyouquans2[j]);
                    pengyouquans2 = remove(pengyouquans2, j);
                    break;
                }
            }
            returnLists = add(returnLists, pengyouquans1[i]);
        }
        for (int j = 0; j < pengyouquans2.length; j++) {
            returnLists = add(returnLists, pengyouquans2[j]);
        }

        /*
         * for (int i = 0; i < returnLists.length; i++) { System.out.println(start + ":"
         * + end + "----" + Arrays.toString(returnLists[i])); }
         */
        return returnLists;
    }

    private static int[][] remove(int[][] pengyouquans2, int j) {
        int[][] pengyouquans = new int[pengyouquans2.length - 1][];
        for (int i = 0; i < j; i++) {
            pengyouquans[i] = pengyouquans2[i];
        }
        for (int i = j; i < pengyouquans.length; i++) {
            pengyouquans[i] = pengyouquans2[i + 1];
        }
        return pengyouquans;
    }

    private static int[] addAll(int[] is, int[] is2) {
        int isLength = is.length;
        is = Arrays.copyOfRange(is, 0, is.length + is2.length);
        for (int i = 0; i < is2.length; i++) {
            is[isLength + i] = is2[i];
        }
        return is;
    }

    private static int[][] add(int[][] returnLists, int[] is) {
        returnLists = Arrays.copyOfRange(returnLists, 0, returnLists.length + 1);
        returnLists[returnLists.length - 1] = is;
        return returnLists;
    }

    // public static Map<Integer,Integer> panDuanMap = new
    // HashMap<Integer,Integer>();
    private static boolean shebeiPanDuan(int[] shebei, int i, int j) {// 将记录保存,保证相同设备两次判断都是一致的
        if (shebei[i] == shebei[j] && shebei[j] == 0) {
            return true;
        }
        if (shebei[i] != shebei[j]) {
            return false;
        }
        return random.nextInt(2) == 0;
    }
}

补充:我是来打自己脸的,虽然分治法能找到,但是发现一个更好的方法。
就是依次查找,使用第一个设备和后面依次比较,如果好的个数大于一半,则成功,把次设备编号返回。
优点:平均时间很快,因为设备数大于半数,所有期望值很低,只有2次,就是2n次比较。
缺点:设备好坏要比较均匀,如果前半区主要是坏设备,那就比较惨了。
时间比较:
一亿条数据:使用二分法22.332s,最后形成27个圈
使用直接查询1.487(第一个设备是好的(以0开始)),如果前27个都是坏的,第27个才是好的,时间22.662s,和分治法差不多

static int sheBeiNum = 100000000;
    static Random random = new Random();

    public static void main(String[] args) {
        int[] shebei = new int[sheBeiNum];
        for (int i = 0; i < shebei.length; i++) {
            /*
             * if(i<100) { shebei[i] = 1; continue; }
             */// 前100个都不是的情况下,也能成功
            shebei[i] = random.nextInt(19) % 2;// 0代表好设备
        }
        for (int i = 0; i < 27; i++) {
            /*
             * if(i<100) { shebei[i] = 1; continue; }
             */// 前100个都不是的情况下,也能成功
            shebei[i] = 1;// 0代表好设备
        }
        shebei[27] = 0;
        int breakNum = 0;
        for (int i = 0; i < shebei.length; i++) {
            breakNum += shebei[i];
        }
        if (sheBeiNum - breakNum <= sheBeiNum / 2) {
            System.out.println("好的设备太少");
            return;
        }
        long stratTime = System.currentTimeMillis();
        int goodNum = 0;
        for (int i = 0; i < shebei.length; i++) {
            goodNum = 0;
            for (int j = i+1; j < shebei.length; j++) {
                if(shebeiPanDuan(shebei,i,j)) {
                    goodNum++;
                }
            }
            if(goodNum>shebei.length/2) {
                System.out.println("第"+i+"设备是好的");
                break;
            }
            breakNum += shebei[i];
        }
        // System.out.println(Arrays.toString(shebei));
        //System.out.println(findOneGood2(shebei));
        long endTime = System.currentTimeMillis();
        System.out.println("VLSI2时间:" + (endTime - stratTime));
    }

猜你喜欢

转载自blog.csdn.net/qq_33321609/article/details/81454717