数字化婚姻匹配问题——优化版(1000组数据3~4分钟)

思路:
读取文件数据,拿到数据逐个加入主角开始匹配,题目要求是给每个主角找到对象(优化点①:主角匹配到对象就可以跳出循环进行下一个主角的匹配了,不必管其他非主角的匹配,如果主角进行了100次都没匹配到,那就进行下一个主角匹配,这种情况最坏),加入主角之后,匹配开始(注意,每次加入主角,他们面对的样本数据都是一样的,即每个主角匹配的时候拿男性样本、女性样本的副本操作),所有男性依次选择自己心仪的女性并发出邀请,然后,受邀次数最多的女性开始选择自己喜欢的男性,在样本(也就是传的副本)中剔除这一对,这个女性已经被一位男性匹配了,那么选择该女性的其他男性只能重新选择自己心仪地女性并发出邀请了(优化点②:这个时候,选择该女性的其他男性重新选择自己心仪地女性即可,不需要所有男性都重新选择一次),之后继续匹配,直到匹配到主角或者匹配次数用完为止,接着打印出匹配结果即可;

/**
 * @ClassName Sex 性别
 * @Description
 * @Author lzq
 * @Date 2019/2/24 16:31
 * @Version 1.0
 **/
public class Sex {
    public static final int MALE = 1;
    public static final int FEMALE = 0;
}
/**
 * @ClassName Sample
 * @Description 样本
 * @Author lzq
 * @Date 2019/2/24 16:27
 * @Version 1.0
 **/
public class Sample {
    private int id;  //样本的ID
    private int appearance;  //样本的样貌
    private int conduct;  //样本的品行
    private int treasure;  //样本的财富

    //样本对这三项指标的要求
    private int appearance1;
    private int conduct1;
    private int treasure1;

    private Sample by_select = null; //匹配对象

    private int sex; //样本的性别


    public Sample(int id, int appearance, int conduct, int treasure, int appearance1,
                  int conduct1, int treasure1, int sex) {
        this.id = id;
        this.appearance = appearance;
        this.conduct = conduct;
        this.treasure = treasure;
        this.appearance1 = appearance1;
        this.conduct1 = conduct1;
        this.treasure1 = treasure1;
        this.sex = sex;
        this.by_select = null;
    }

    public void setBy_select(Sample by_select) {
        this.by_select = by_select;
    }

    public Sample getBy_select() {
        return by_select;
    }

    public int getSex() {
        return sex;
    }

    public int getId() {
        return id;
    }

    public int getAppearance() {
        return appearance;
    }

    public int getConduct() {
        return conduct;
    }

    public int getTreasure() {
        return treasure;
    }

    public int getAppearance1() {
        return appearance1;
    }

    public int getConduct1() {
        return conduct1;
    }

    public int getTreasure1() {
        return treasure1;
    }

}
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * @ClassName Read
 * @Description 读取
 * @Author lzq
 * @Date 2019/2/24 17:38
 * @Version 1.0
 **/
public class Read {
    /**
     * 读取男性、女性样本数据
     * @param file
     * @param sex
     * @return
     */
    public static ArrayList<Sample> get_sample_data(String file, int sex){
        ArrayList<Sample> list = new ArrayList<>();
        Scanner scanner = null;
        try {
            scanner = new Scanner(new File(file));
            String line_data;
            String[] data;
            while (scanner.hasNextLine()) {
                line_data = scanner.nextLine();
                data = line_data.split(",");
                list.add(new Sample(Integer.valueOf(data[0]),Integer.valueOf(data[1]),
                        Integer.valueOf(data[2]),Integer.valueOf(data[3]),
                        Integer.valueOf(data[4]),Integer.valueOf(data[5]),
                        Integer.valueOf(data[6]),sex));
            }
        }catch (FileNotFoundException e) {
            System.out.println("读取失败!");
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 读取主角样本数据
     * @param file
     * @param id
     * @return
     */
    public static ArrayList<Sample> get_player_data(String file,int id){
        ArrayList<Sample> list = new ArrayList<>();
        Scanner scanner = null;
        try {
            scanner = new Scanner(new File(file));
            String line_data;
            String[] data;
            while (scanner.hasNextLine()) {
                line_data = scanner.nextLine();
                data = line_data.split(",");
                list.add(new Sample(id,Integer.valueOf(data[1]),
                        Integer.valueOf(data[2]),Integer.valueOf(data[3]),
                        Integer.valueOf(data[4]),Integer.valueOf(data[5]),
                        Integer.valueOf(data[6]),Integer.valueOf(data[0])));
            }
        }catch (FileNotFoundException e) {
            System.out.println("读取失败!");
            e.printStackTrace();
        }
        return list;
    }
}
import java.util.*;


/**
 * @ClassName Matching
 * @Description 匹配
 * @Author lzq
 * @Date 2019/2/24 16:52
 * @Version 1.0
 **/
public class Matching {
    private ArrayList<Sample> male;  //男生样本
    private ArrayList<Sample> female;  //女生样本
    private ArrayList<Sample> players;  //存储主角样本数据

    private int count = 1; //计数器


    private int size = 0;


    /**
     * 初始化
     * @param size
     */
    public Matching(int size) {
        this.male = new ArrayList<>(size);
        this.female = new ArrayList<>(size);
        this.size = size;
    }

    /**
     * 公共接口,传入路径,读取数据
     * @param path1
     * @param path2
     * @param path
     */
    public void begin(String path1, String path2, String path) {
        ArrayList<Sample> man = Read.get_sample_data(path1, Sex.MALE);
        ArrayList<Sample> woman = Read.get_sample_data(path2, Sex.FEMALE);
        this.players = Read.get_player_data(path, -1);
        join_player(man,woman);
    }

    /**
     * 逐个加入主角,开始匹配
     * @param man
     * @param woman
     */
    private void join_player(ArrayList<Sample> man,ArrayList<Sample> woman) {
        for (Sample next : players) {
            male = (ArrayList<Sample>) man.clone();  //拿到副本
            female = (ArrayList<Sample>) woman.clone();
            start(next);
        }
    }


    /**
     * 匹配开始
     * @param player
     */
    private void start(Sample player) {
        if(player.getSex() == Sex.MALE) {
            male.add(player);
        }else {
            female.add(player);
        }
        male_select_female(player);
    }

    /**
     * 男性选择女性
     * @param player
     */
    private void male_select_female(Sample player) {
        HashMap<Sample,ArrayList<Sample>> hashmap = new HashMap<>();
        Sample best = null;

        //所有男性开始选择女生
        for (Sample next : male) {
            best = select_most(next,female); //拿到当前男生选择的最合适的女性
            boolean flag = hashmap.containsKey(best); //判断该女性有没有被其他人选

            //将其加入HashMap
            if(flag) {
                ArrayList<Sample> list = hashmap.get(best);
                list.add(next);
            }else {
                ArrayList<Sample> list = new ArrayList<>();
                list.add(next);
                hashmap.put(best,list);
            }
        }

        for (int i = 0; i < size; i++) {  //进行最多100次匹配,直到主角被选上为止

            //男性选择完毕,女性开始反选
            Sample max_female = most_female(hashmap); //得到受邀最多的女性
            List<Sample> list = female_select_male(max_female,hashmap);
            if(player.getBy_select() != null) {  //如果主角已经被选取,跳出循环
                break;
            }else {  //如果主角没有被选取,那选择该女性的男性集合里的男性重选
                //优化点:不需要剩下的所有男性都再选一次
                Iterator<Sample> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Sample next = iterator.next(); //得到其中一个男性
                    Sample max_best = select_most(next,female); // 得到该男生新的最满意的女性
                    boolean flag = hashmap.containsKey(max_best); //判断该女性有没有被其他人选

                    //将其加入HashMap
                    if(flag) {
                        ArrayList<Sample> list1 = hashmap.get(max_best);
                        list1.add(next);
                    }else {
                        ArrayList<Sample> list1 = new ArrayList<>();
                        list1.add(next);
                        hashmap.put(max_best,list1);
                    }
                }
            }
        }
        show(player);
    }

    /**
     * 女生反选
     * @param max_female
     * @param hashmap
     * @return
     */
    private List<Sample> female_select_male(Sample max_female, HashMap<Sample,ArrayList<Sample>> hashmap) {
        ArrayList<Sample> list = hashmap.get(max_female);  //得到受邀最多女性的所有男性集合
        Sample best = select_most(max_female,list); //得到该女性最满意的对象
        max_female.setBy_select(best);
        best.setBy_select(max_female);
        male.remove(best);
        female.remove(max_female);
        list.remove(best);  //将该集合里面被选择的男性删除
        return list;
    }


    /**
     * 得到被邀请次数最多的女生
     * @param hashmap
     * @return
     */
    private Sample most_female(HashMap<Sample,ArrayList<Sample>> hashmap) {
        int maxFemaleNum = 0;
        Sample maxFemale = null;
        for (Sample next : female) {
            ArrayList<Sample> list = hashmap.get(next);
            if(list != null) {
                if(list.size() == maxFemaleNum) {
                    maxFemale = select(next,maxFemale);
                }else if(list.size() > maxFemaleNum) {
                    maxFemale = next;
                    maxFemaleNum = list.size();
                }
            }
        }
        return maxFemale;
    }

    /**
     * 选择最合适的
     * @param next
     * @param female
     * @return
     */
    private Sample select_most(Sample next, ArrayList<Sample> female) {
        Sample best = null; //最终拿到的最合适的人
        int max = 0;
        for (Sample present : female) {
            int score = score(next,present);
            if(score > max) {
                best = present;
                max = score;
            }else if(score == max) {
                best = select(best,present);
            }
        }
        return best;
    }


    /**
     * 当满意度相同时、通过总和、id选择最合适的
     * @param present
     * @param best
     * @return
     */
    private Sample select(Sample present, Sample best) {
        int sum1 = present.getAppearance()+present.getConduct()+present.getTreasure();
        int sum2 = best.getAppearance()+best.getConduct()+best.getTreasure();
        if(sum1 > sum2) {
            return present;
        }else {
            if(sum1 == sum2) {
                return present.getId() < best.getId() ? present : best;
            }
            return best;
        }
    }


    /**
     * 获取满意度
     * @param select 选择者
     * @param be_select 被选择者
     * @return
     */
    private int score(Sample select,Sample be_select) {
        int score = select.getAppearance1()*be_select.getAppearance()+
                select.getConduct1()*be_select.getConduct()+
                select.getTreasure1()*be_select.getTreasure();
        return score;
    }

    /**
     * 打印
     * @param player
     */
    private void show(Sample player) {
        if(player.getBy_select() != null) {
            if (player.getSex() == Sex.MALE) {
                System.out.println("第" + count++ + "组主角加入:" + player.getId() + ":" +
                        player.getBy_select().getId());
            } else {
                System.out.println("第" + count++ + "组主角加入:" + player.getBy_select().getId() + ":" +
                        player.getId());
            }
        }else {
            System.out.println("第"+count+++"组主角加入:");
        }
    }
public class TestDemo1 {
    public static void main(String[] args) {
        String file1 = "F:/zy/temp100/male.txt";
        String file2 = "F:/zy/temp100/female.txt";
        String file3 = "F:/zy/temp100/players.txt";
        long s = System.currentTimeMillis();
        Matching matching = new Matching(size);
        matching.begin(file1,file2,file3);
        long e = System.currentTimeMillis();
        System.out.println((e-s)/1000/60);
    }
}

100组数据运行结果:
在这里插入图片描述
在这里插入图片描述
1000组数据:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/QQ2899349953/article/details/87965510