朋友圈(java版)

7-8 朋友圈 (25 分)

某学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出,如果A和B是朋友,且B和C是朋友,则A和C也是朋友。请编写程序计算最大朋友圈中有多少人。

输入格式:

输入的第一行包含两个正整数N(≤30000)和M(≤1000),分别代表学校的学生总数和俱乐部的个数。后面的M行每行按以下格式给出1个俱乐部的信息,其中学生从1~N编号:

第i个俱乐部的人数Mi(空格)学生1(空格)学生2 … 学生Mi

输出格式:

输出给出一个整数,表示在最大朋友圈中有多少人。

输入样例:

7 4
3 1 2 3
2 1 4
3 5 6 7
1 6

输出样例:

4

思路:第一,首先找到同组的,然后把同组的id值变为一样的,然后继续寻找是否有同组的其中的元素,举列子,以这道题为例,因为第一组第一个学生编号为1,所以id值为1,所以其他的两个学生编号的id值也是1,这样他们三个是同一个集合,现在寻找其他集合中是否有id值为1的,然后把剩下的元素id变为1,这样就全部合并了。

反思和总结:拿到此题,发现是并查集,于是去看了并查集,然后发现,看过还是操作有点困难,然后写了这道题目,在我博客的上一篇当中有并查集的几种方法的总结。然后非想用写并查集的类来操作,于是写了一个并查集的实现。期间数组总是越界,因为开始定义的都是初始长度,也就是学生的人数,发现索引和值不匹配,于是改了 n次,最后成功,把初始值传进来时候加一数组长度变为8,这样就可以把0置为0,a[7]=7,千方百计得出了答案,发现最后一个测试点还是超时。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt(); //多少个学生
        int m = sr.nextInt();//多少组朋友圈
        UnionFind su = new UnionFind(n+1);
        for (int i=0;i<m;i++){
            int a = sr.nextInt(); //每组多少人数
            int b = sr.nextInt(); //开始输入第一个学生编号
            a--;
            for (int j=1;j<=a;j++){
                int c = sr.nextInt();//第二个学生编号
                su.unionElements(b,c); //开始连接 循环链接 第一个 到第二个,第一个和第三个,只要每组有多少人都会连接
            }

        }
        su.results();

    }



}
class UnionFind{
    private int [] id ;//初始定义的数组
    public UnionFind(int size){
        id = new int[size];
        for (int i=0;i<id.length;i++){
            id[i]=i;//把每个id相当于集合的索引设置初始的值
        }
    }
    public int getSize() {
        return id.length;
    }
    //查找元素p所对应的集合编号
    public int find(int p){
        if (p <0 && p>=id.length)
            throw new IllegalArgumentException("p is out of bound");
        return id[p];
    }
    //用于查看元素p和元素q是否属于同一个集合

    public boolean isConnected(int p, int q) {
        return find(p)==find(q);
    }
    //

    public void unionElements(int p, int q) {
        int pid = find(p);
        int qid = find(q);
        if (pid == qid) {
            return;
        }
        for (int i = 0; i < id.length; i++) {
            if (id[i] == pid) {
                id[i] = qid;
            }
        }
    }
    public void results(){
        //进行排序找到每个对应的第一个元素
        for (int i = 1; i < id.length; i++) {
            id[i] = find(i); //查找元素对应的编号
        }
        Arrays.sort(id);//对数组进行排序
        int sum = 1,maxn = 0;
        for (int i=2;i<id.length;i++){
            if (id[i]==id[i-1]){
                sum++; //遇到值相等加一
            }else {
                maxn = Math.max(sum, maxn); //进行比较
            }
        }
        System.out.println(maxn);
    }
}

 第二个方法  我放在一个类当中,只用了并查集的两个方法,发现依旧超时:虽然代码优化了一点吧!

import java.util.Arrays;
import java.util.Scanner;

public class demo {
    private int [] id ;//初始定义的数组
    public demo(int size){
        id = new int[size];
        for (int i=0;i<id.length;i++){
            id[i]=i;//把每个id相当于集合的索引设置初始的值
        }
    }
    //查找元素p所对应的集合编号
    public  int  find(int p){
        return id[p];
    }
    //用于查看元素p和元素q是否属于同一个集合
    public  boolean isConnected(int p, int q) {
        return find(p)==find(q);
    }
    //

    public void unionElements(int p, int q) {
        int pid = find(p);
        int qid = find(q);
        if (pid == qid) {
            return;
        }
        for (int i = 0; i < id.length; i++) {
            if (id[i] == pid) {
                id[i] = qid;
            }
        }
    }
    public void results(){
        //进行排序找到每个对应的第一个元素
        for (int i = 1; i < id.length; i++) {
            id[i] = find(i); //查找元素对应的编号
        }
        Arrays.sort(id);
        int sum = 1,maxn = 0;
        for (int i=2;i<id.length;i++){
            if (id[i]==id[i-1]){
                sum++;
            }else {
                maxn = Math.max(sum, maxn); //进行比较
            }
        }
        System.out.println(maxn);
    }

    public static void main(String[] args){
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt(); //多少个学生
        int m = sr.nextInt();//多少组朋友圈
        demo d = new demo(n+1);
        for (int i=0;i<m;i++){
            int a = sr.nextInt(); //每组多少人数
            int b = sr.nextInt(); //开始输入第一个学生编号
            a--;
            for (int j=1;j<=a;j++){
                int c = sr.nextInt();//第二个学生编号
                d.unionElements(b,c); //开始连接 循环链接 第一个 到第二个,第一个和第三个,只要每组有多少人都会连接
            }

        }
       d.results();
    }
}

第二个方法(树):

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    private int [] parent ;//初始定义的数组
    public Main(int size){
        parent = new int[size];
        for (int i=0;i<parent.length;i++){
            parent[i]=i;//把每个parent相当于集合的索引设置初始的值
        }
    }
    //查找元素p所对应的集合编号
    public  int  find(int p){
        while(p!=parent[p]){
            p=parent[p];
        }
        return p;
    }
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) {
            return;
        }
        parent[pRoot]=qRoot;//指向根节点即可
    }
    public void results(){
        //进行排序找到每个对应的第一个元素
        for (int i = 1; i < parent.length; i++) {
            parent[i] = find(i); //查找元素对应的编号
        }
        Arrays.sort(parent);
        int sum = 1,maxn = 0;
        for (int i=2;i<parent.length;i++){
            if (parent[i]==parent[i-1]){
                sum++;
            }else {
                maxn = Math.max(sum, maxn); //进行比较
            }
        }
        System.out.println(maxn);
    }

    public static void main(String[] args){
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt(); //多少个学生
        int m = sr.nextInt();//多少组朋友圈
        Main d = new Main(n+1);
        for (int i=0;i<m;i++){
            int a = sr.nextInt(); //每组多少人数
            int b = sr.nextInt(); //开始输入第一个学生编号
            a--;
            for (int j=1;j<=a;j++){
                int c = sr.nextInt();//第二个学生编号
                d.unionElements(b,c); //开始连接 循环链接 第一个 到第二个,第一个和第三个,只要每组有多少人都会连接
            }

        }
        d.results();
    }
}
同样超时!!!

第三个方法 :改变了输入输出方式依旧超时:最后放弃!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
    private int [] parent ;//初始定义的数组
    public Main(int size){
        parent = new int[size];
        for (int i=0;i<parent.length;i++){
            parent[i]=i;//把每个parent相当于集合的索引设置初始的值
        }
    }
    //查找元素p所对应的集合编号
    public  int  find(int p){
        while(p!=parent[p]){
            p=parent[p];
        }
        return p;
    }
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) {
            return;
        }
        parent[pRoot]=qRoot;//指向根节点即可
    }
    public void results(){
        //进行排序找到每个对应的第一个元素
        for (int i = 1; i < parent.length; i++) {
            parent[i] = find(i); //查找元素对应的编号
        }
        Arrays.sort(parent);
        int sum = 1,maxn = 0;
        for (int i=2;i<parent.length;i++){
            if (parent[i]==parent[i-1]){
                sum++;
            }else {
                maxn = Math.max(sum, maxn); //进行比较
            }
        }
        System.out.println(maxn);
    }

    public static void main(String[] args)throws IOException {
        BufferedReader sr = new BufferedReader(new InputStreamReader(System.in));
        String s = sr.readLine();
        int n = Integer.parseInt(s.split(" ")[0]);  //多少个学生
        int m = Integer.parseInt(s.split(" ")[1]);//多少组朋友圈
        Main d = new Main(n+1);
        for (int i=0;i<m;i++){
            String ss[] = sr.readLine().split(" ");
            int a = Integer.parseInt(ss[0]); //每组多少人数
            int b = Integer.parseInt(ss[1]); //开始输入第一个学生编号
            a--;
                for (int j=1;j<=a;j++){
                    int c = Integer.parseInt(ss[j+1]);//第二个学生编号
                    d.unionElements(b,c); //开始连接 循环链接 第一个 到第二个,第一个和第三个,只要每组有多少人都会连接
            }
        }
        d.results();
    }
}

第四中加入了树的节点判断,然而崩溃,还是超时,真放弃了!!!!!

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    private int [] parent ;//初始定义的数组
    private int [] sz;
    public Main(int size){
        parent = new int[size];
        sz = new int[size];
        for (int i=0;i<parent.length;i++){
            parent[i]=i;//把每个parent相当于集合的索引设置初始的值
            sz[i]=1;
        }
    }
    //查找元素p所对应的集合编号
    public  int  find(int p){
        while(p!=parent[p]){
            p=parent[p];
        }
        return p;
    }
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) {
            return;
        }
        if (sz[pRoot]<sz[qRoot]){
            parent[pRoot]=qRoot;//p个几点所在的个数相对于比较少,让元素个数比较少的指向元素个数比较多的根节点
            sz[qRoot]+=sz[pRoot];
        }else{
            parent[qRoot]=pRoot;
            sz[pRoot]+=sz[qRoot];
        }
    }
    public void results(){
        //进行排序找到每个对应的第一个元素
        for (int i = 1; i < parent.length; i++) {
            parent[i] = find(i); //查找元素对应的编号
        }
        Arrays.sort(parent);
        int sum = 1,maxn = 0;
        for (int i=2;i<parent.length;i++){
            if (parent[i]==parent[i-1]){
                sum++;
            }else {
                maxn = Math.max(sum, maxn); //进行比较
            }
        }
        System.out.println(maxn);
    }

    public static void main(String[] args){
        Scanner sr = new Scanner(System.in);
        int n = sr.nextInt(); //多少个学生
        int m = sr.nextInt();//多少组朋友圈
        Main d = new Main(n+1);
        for (int i=0;i<m;i++){
            int a = sr.nextInt(); //每组多少人数
            int b = sr.nextInt(); //开始输入第一个学生编号
            a--;
            for (int j=1;j<=a;j++){
                int c = sr.nextInt();//第二个学生编号
                d.unionElements(b,c); //开始连接 循环链接 第一个 到第二个,第一个和第三个,只要每组有多少人都会连接
            }

        }
        d.results();
    }
}

 

猜你喜欢

转载自blog.csdn.net/qq_41479464/article/details/88312572