• QQ简易版


    package QQ;
    /*
    * 
    * 登录界面
    * */
    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    
    public  class QQLogin extends JFrame {
    
        public  QQLogin() {
            setTitle("登录");
            setSize(300, 200);
            setLocationRelativeTo(null);//设置居中
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLayout(null);
            JLabel usernameText = new JLabel("账号");
            usernameText.setBounds(30, 30, 60, 30);
            JLabel passwordText = new JLabel("密码");
            passwordText.setBounds(30, 60, 60, 30);
            add(usernameText);
            add(passwordText);
            final JTextField username = new JTextField();
            final JPasswordField password = new JPasswordField();
            username.setBounds(100, 30, 120, 30);
            password.setBounds(100, 60, 120, 30);
            add(username);
            add(password);
            //注册按钮
            JButton reg=new JButton("注册");
            reg.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    new QQReg().setVisible(true);//打开注册页面
                    QQLogin.this.dispose();//关闭登录页面
                }
            });
            reg.setBounds(150,110,80,30);
            add(reg);
    
            //登录
            JButton login = new JButton("登录");
            login.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    //获取账号密码
                    Message message = new Message();
                    message.setType(Message.LOGIN); //获取注注册类型
                    message.setUsername(username.getText());//获取输入框输入名称
                    message.setPassword(new String(password.getPassword())); //获取输入框输入密码
                    try {
                        Socket socket = new Socket("127.0.0.1", 8888);  //连接服务器
                        ObjectRW.writeObject(message, socket); //调用ObjectRW的静态方法writeObject 并把message, socket的对象传入进去调用方法之后传入到服务器
                        message = (Message) ObjectRW.readObject(socket);  //调用ObjectRW中的readObject方法 获取message信息
                        if (message.getType() == Message.RESULT && message.isSuccess()) {
                            //弹窗
    //                        JOptionPane.showConfirmDialog(null, "登录成功", "提示", JOptionPane.YES_OPTION);
                            QQLogin.this.setVisible(false);//隐藏登录界面
                            new Friends(socket,username.getText()).setVisible(true);
    //                        QQLogin.this.dispose();
    
                            //开启friends列表界面 并将登录时的socket和名称传过去
                        } else {
                            JOptionPane.showConfirmDialog(null, "登录失败", "提示", JOptionPane.YES_OPTION);
                        }
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            login.setBounds(50, 110, 80, 30);
            add(login);
        }
    
    }
    package QQ;
    /*
    *
    * 注册界面
    * */
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    
    
    public class QQReg extends JFrame {
    
        public QQReg() {
            setTitle("注册");
            setSize(300, 200);
            setLocationRelativeTo(null);//设置居中
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLayout(null);
            JLabel usernameText = new JLabel("账号");
            usernameText.setBounds(30, 30, 60, 30);
            JLabel passwordText = new JLabel("密码");
            passwordText.setBounds(30, 60, 60, 30);
            add(usernameText);
            add(passwordText);
            final JTextField username = new JTextField();
            final JPasswordField password = new JPasswordField();
            username.setBounds(100, 30, 120, 30);
            password.setBounds(100, 60, 120, 30);
            add(username);
            add(password);
            //注册按钮
            JButton reg = new JButton("注册");
            reg.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    //获取账号密码
                    Message message = new Message();
                    message.setType(Message.REG); //获取注注册类型
                    message.setUsername(username.getText());//获取输入框输入名称
                    message.setPassword(new String(password.getPassword())); //获取输入框输入密码
                    try {
                        Socket socket = new Socket("127.0.0.1", 8888);  //连接服务器
                        ObjectRW.writeObject(message, socket); //调用ObjectRW的静态方法writeObject 并把message, socket的对象传入进去调用方法之后传入到服务器
                        message = (Message) ObjectRW.readObject(socket);  //调用ObjectRW中的readObject方法 获取message信息
                        if (message.getType() == Message.RESULT && message.isSuccess()) {
                            //弹窗
    //                        JOptionPane.showConfirmDialog(null, "注册成功", "提示", JOptionPane.OK_OPTION);
                            new QQLogin().setVisible(true);
                            QQReg.this.dispose();
    
                        } else {
                            JOptionPane.showConfirmDialog(null, "注册失败", "提示", JOptionPane.YES_OPTION);
                        }
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            reg.setBounds(100, 110, 80, 30);
            add(reg);
        }
    
    }
    package QQ;
    
    import java.io.Serializable;
    
    public class Message implements Serializable {
        private static final long serialVersionUID = -3021746792251923405L;
        //设为对象流
        private int type = 0;//消息类型
    
        public static final int RESULT = 2;//完成为2
    
        public static final int REG = 1;//初始注册
    
        public static final int LOGIN = 3;//登录
    
        private boolean isSuccess;//是否注册成功
    
        public static final int REFRESH_FRIENDS = 4;//刷新好友列表
        public static final int REFRESH_FRIENDS_RESULT = 5;//刷新好友列表结果
        public static final int SINGLE_MESSAGE = 6;//一对一废话聊天
        public static final int GROUP_MESSAGE = 7;//群聊消息
        public static final  int EXIT =8;//退出程序
        private String from;//消息发送者
        private String to;//消息接受者
        private String content;//消息内容
        private String time;//发送时间
    
        public String getFrom() {
            return from;
        }
    
        public void setFrom(String from) {
            this.from = from;
        }
    
        public String getTo() {
            return to;
        }
    
        public void setTo(String to) {
            this.to = to;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getTime() {
            return time;
        }
    
        public void setTime(String time) {
            this.time = time;
        }
    
        private String[] friends;//所有好友数据
    
        public String[] getFriends() {
            return friends;
        }
    
        public void setFriends(String[] friends) {
            this.friends = friends;
        }
    
        public boolean isSuccess() {
            return isSuccess;
        }
    
        public void setSuccess(boolean isSuccess) {
            this.isSuccess = isSuccess;
        }
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
        private String username;
    
        private String password;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    
    }
    package QQ;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    
    public class ObjectRW {
    
        /**
         * 写出对象
         * @param obj
         * @param socket
         */
        public static void writeObject(Object obj,Socket socket){
            //静态  ObjectRW.writeObject(message, socket);传入的是message对象  Object是父类形成一个多态
            try {
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                oos.writeObject(obj);  //获取socket之后 写出writeObject(obj)写出到服务器的是message里面的信息
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 读取对象
         * @param socket
         * @return
         */
        public static Object readObject(Socket socket){
            try {
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                return ois.readObject();   //获取socket之后  从服务器读取所有相关信息
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null; //如果没有就返回为空
    
        }
    }
    package QQ;
    /*
    * 好友列表
    * */
    import sun.applet.resources.MsgAppletViewer;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Friends extends JFrame {
        private Socket socket;
        private String username;
        private JPanel friends;//一个装列表的容器
        private String[] all;//用来存放好友列表
        private Map<String,Talk> talks = new HashMap<>();//用来存放对话窗口
        // 将用户名 和对应的对话窗口放在一个集合中 方便以后调用该窗口
    
        public Friends(Socket socket, String username) {
            setTitle(username);
            this.socket = socket; //接受登录时自己的socket
            this.username = username; ////接受登录时自己的username
            friends = new JPanel();
            friends.setLayout(new BorderLayout());
            add(friends); //容器添加到框里去
            JButton group =new JButton("群聊"); //------------群聊按钮
            group.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                        showTalk("群聊",Talk.GROUP);
                }
            });
            add(group,BorderLayout.SOUTH);
    
    
    
    //            第一次刷新好友列表
            Message msg = new Message(); //从登陆完成之后从内存中获取相关信息
            msg.setType(Message.REFRESH_FRIENDS);//设置为刷新类型
            ObjectRW.writeObject(msg, socket);//修改之后传入内存中--等待服务器反应
    //            msg = (Message)ObjectRW.readObject(socket);//从内存中获取从服务器返回的msg包里的信息
    //            if(msg.getType() == Message.REFRESH_FRIENDS_RESULT){ //判读是否获取列表成功
    //                refreshFriend(msg); //进行刷新操作
    //            }
            ////启动线程随时能够接收服务器发送过来的消息
            FriendUtil friendUtil = new FriendUtil(socket, this); ///--->FriendUtil
            friendUtil.start();
    
            setSize(150, 500);
            setLocationRelativeTo(null);
            setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);  //退出 告诉服务器
            //添加窗口事件
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    Message msg =new Message();
                    msg.setType(Message.EXIT);
                    msg.setUsername(username);
                    ObjectRW.writeObject(msg,socket);
                    System.exit(0);//退出程序
                }
            });
    
    
        }
    
        /**
         * 刷新
         *
         * @param msg
         */
        public void refreshFriend(Message msg) {
            friends.removeAll();//移除容器之前中的组件
            all =msg.getFriends();
            JList list = new JList(all);//将获取到的好友列表信息写入列表中  msg.getFriends()好友列表
            //鼠标事件 对好友列表进行操作
            list.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    //判断是否双击
                    if(e.getClickCount()==2){
                        //根据鼠标位置判断点击的是第几个
                        int index = list.locationToIndex(e.getPoint());//返回一个数字
                        //all[index]根据好友列表数组得到接受者
                        //并打开聊天窗口
                        showTalk(all[index],Talk.SINGLE);
                    }
    
                }
            });
    
            friends.add(list);
            friends.repaint();
            friends.updateUI();//刷新
        }
    
        /**
         * 显示聊天窗口
         * @param name
         */
        public Talk showTalk(String name,int type){  //聊天窗口类
            Talk talk =talks.get(name); //talks 是聊天窗口的集合 通过名字获得该窗口
            if(talk ==null){ //如果之前没有这个窗口就创建一个新的窗口
                talk = new Talk(name,socket,username,type);// --------->调用talk构造方法   打开对话窗口方法
                talks.put(name,talk); //将接受者的名字和他的窗口放进集合
            }
            if(!talk.isVisible()){  //如果该窗口没有显示才显示窗口
                talk.setVisible(true);
            }
            return talk;
        }
    }
    package QQ;
    /*
    *
    *
    * */
    import java.net.Socket;
    
    public class FriendUtil extends Thread {
        private Socket socket;
        private Friends friends;
    
        public FriendUtil(Socket socket, Friends friends) {
            this.socket = socket;
            this.friends = friends;
        }
    
        @Override
        public void run() {    //通过friends中线程启动随时能够接收服务器发送过来的消息
            super.run();
            while (true) {
                Message msg = (Message) ObjectRW.readObject(socket);
                if (msg.getType() == Message.REFRESH_FRIENDS_RESULT) {
                    friends.refreshFriend(msg); //刷新每一个的列表
                } else if (msg.getType() == Message.SINGLE_MESSAGE) {
                    Talk talk = friends.showTalk(msg.getFrom(), Talk.SINGLE);  ///---->>>friends.showTalk   msg.getFrom()发送者的名称
                    //开启一个接受者的窗口并将发送者作为你的窗口的接受者
                    talk.showMessage(msg.getFrom(), msg.getContent(), msg.getTime());
                    //---->talk.showMessage在接受者的窗口显示接受消息
                } else if (msg.getType() == Message.GROUP_MESSAGE) {
                    Talk talk = friends.showTalk("群聊", Talk.GROUP);  ///---->>>friends.showTalk   msg.getFrom()发送者的名称
                    //开启一个接受者的窗口并将发送者作为你的窗口的接受者
                    talk.showMessage(msg.getFrom(), msg.getContent(), msg.getTime());
                }
            }
        }
    }

    package QQ;
    /*
    * 聊天
    *
    * */
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.net.Socket;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Talk extends JFrame {
        private String to;
        private Socket socket;
        private String from;
    
        private  int type; //-----------区分群聊
        public static final int SINGLE = 1;//一对一废话聊天
        public static final int GROUP= 2;//群聊消息
    
        private JTextArea show;//消息接受显示框
        private JTextArea input;//消息发送显示框
    
    
        public Talk(String to, Socket socket, String from,int type) {  //从Friends中showTalk方法调用该构造方法   talk = new Talk(name,socket,username);//调用talk
            this.to = to;
            this.socket = socket; //消息内容所需要的
            this.from = from;
            this.type =type;
    
            setSize(200, 350);
            setLocationRelativeTo(null);
            setTitle(to);
            show = new JTextArea();
            show.setEditable(false);//设置不可编辑
            show.setBorder(BorderFactory.createLineBorder(Color.gray));//设置边框
    
            input = new JTextArea();
            JButton btn = new JButton("发送");//发送按钮
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Message msg = new Message();
                    if(type ==Talk.SINGLE){
                        msg.setType(Message.SINGLE_MESSAGE);//聊天类型 一对一
                    }else {
                        msg.setType(Message.GROUP_MESSAGE);//聊天类型 群聊
                    }
    
                    msg.setFrom(from);
                    msg.setTo(to);
                    msg.setContent(input.getText());//聊天消息内容 content
                    //设置发送时间
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    msg.setTime(sdf.format(new Date()));//发送时当前时间
                    ObjectRW.writeObject(msg,socket); //写入通道传给服务器 ----->到服务器
                    showMessage(from,input.getText(),sdf.format(new Date())); //在发送者界面显示已经发送的消息
                    input.setText("");//发送信息后清空发送框
    
                }
            });
            JScrollPane jsc = new JScrollPane(show);
            jsc.setPreferredSize(new Dimension(0, 200));
            add(jsc,BorderLayout.NORTH);
            add(new JScrollPane(input),BorderLayout.CENTER);
            add(btn,BorderLayout.SOUTH);
            setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        }
        /*
        * 显示消息
        * */
        public void showMessage(String name,String content,String time){
            //显示消息
            show.append(name);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            show.append("     " + time + "
    ");
            show.append(content + "
    ");
        }
    }
    package QQ;
    /*
    *
    * 服务器端
    * */
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;
    
    public class QQserver {
        ServerSocket serverSocket;
        private Map<String, Socket> sockets = new HashMap<>();//这里有线程安全的问题
    
        public QQserver() {
            try {
                serverSocket = new ServerSocket(8888);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /*
         *
         * 开启服务器
         * */
        public void start() {
            while (true) {
                try {
                    Socket socket = serverSocket.accept();//开启
                    Message msg = (Message) ObjectRW.readObject(socket);
                    if (msg.getType() == Message.REG) {
                        msg.setType(Message.RESULT);
                        msg.setSuccess(reg(msg));
                        ObjectRW.writeObject(msg, socket);
                    } else if (msg.getType() == Message.LOGIN) {
                        msg.setType(Message.RESULT);
                        boolean flag = login(msg);
                        msg.setSuccess(flag);
                        ObjectRW.writeObject(msg, socket);
                        if(flag){//登录成功之后进行列表信息操作
                            sockets.put(msg.getUsername(), socket);//保存其余所有登录成功时的通道和用户名到集合里面
                            //启动一个专门针对一个用户服务的线程
                            new QQservice(socket,sockets).start();
                        }
    
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /*
         * 执行注册
         * */
        public boolean reg(Message msg) {
    
            return Sqlutil.reg(msg);
        }
    
        /*
         *
         * 执行登录
         * */
        public boolean login(Message msg) {
    
    
            return Sqlutil.login(msg);
        }
    
    
    }
    package QQ;
    
    import java.io.IOException;
    import java.net.Socket;
    import java.util.Map;
    import java.util.Set;
    
    public class QQservice extends Thread {
        private Socket socket;
        private Map<String, Socket> sockets;
    
        public QQservice(Socket socket, Map<String, Socket> sockets) {
            this.socket = socket; //当前登录并刷新时自己的socket
            this.sockets = sockets;//其他人登录时保存的username和socket
        }
    
        @Override
        public void run() {
            while (true) { //刷新时需要可复用
                Message msg = (Message) ObjectRW.readObject(socket);//读取写入内存中的信息
                if (msg.getType() == Message.REFRESH_FRIENDS) {//----------判断为获取好友列表操作
                    msg.setType(Message.REFRESH_FRIENDS_RESULT);//修改刷新完成类型
                    msg.setFriends(getFriends());//获取好友列表并写入msg中
    //                ObjectRW.writeObject(msg, socket); 只是刷新给当前登录的那个人
    //                刷新给所有人
                    Set<String> sets = sockets.keySet();
                    for (String name : sets) { //每次循环 给每个登录的人
                        ObjectRW.writeObject(msg, sockets.get(name)); //将修改的msg和socket写回每一个人中的内存中
                    }
                } else if (msg.getType() == Message.SINGLE_MESSAGE) {  //>>>>-------判断为一对一聊天操作读取talk发送过来的内容
                    Socket to = sockets.get(msg.getTo()); //通过 sockets集合 接受者的sockets (连接方式)
                    ObjectRW.writeObject(msg, to);//将信息发送给需要接受的人
                } else if (msg.getType() == Message.GROUP_MESSAGE) {//----------判断为群聊操作
    //                ObjectRW.writeObject(msg, socket); 只是刷新给当前登录的那个人
    //                刷新给所有人
                    Set<String> sets = sockets.keySet();
                    for (String name : sets) { //每次循环 给每个登录的人
                        if (!name.equals(msg.getFrom())) { //不需要给自己发送群聊消息
                            ObjectRW.writeObject(msg, sockets.get(name)); //将修改的msg和socket写回每一个人中的内存中
                        }
                    }
                } else if (msg.getType() == Message.EXIT) {
                    //退出
                    //从集合中移除
                    sockets.remove(msg.getUsername());
                    msg.setType(Message.REFRESH_FRIENDS_RESULT);//修改刷新完成类型
                    msg.setFriends(getFriends());//获取好友列表并写入msg中
                    Set<String> sets = sockets.keySet();
                    for (String name : sets) { //每次循环 给每个登录的人
                        ObjectRW.writeObject(msg, sockets.get(name)); //将修改的msg和socket写回每一个人中的内存中
                    }
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        }
    
        /**
         * 获取所有的好友数据
         *
         * @return
         */
    
        public String[] getFriends() {
            Set<String> names = sockets.keySet(); //将好友列表的信息设为set集合
            String friends[] = new String[names.size()];
            names.toArray(friends); //将set中的信息写到集合中去 返回一个好友列表的集合
            return friends;
        }
    }
    package QQ;
    
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    
    /*
     * 连接数据库并进行添加操作
     *
     *
     * */
    public class Sqlutil {
    
        static {
            try {  //加载驱动  方法块
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        public static Connection getConnection() {
            try {  //连接数据库
                return DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "123456");
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    
        //关闭连接
        public static void colse(ResultSet rs, PreparedStatement pst, Connection conn) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (pst != null) {
                try {
                    pst.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        //进行注册功能并写入数据库
        public static boolean reg(Message msg) {
            String sql = "insert into user (user,password)values (?,?)";
            Connection conn = getConnection();//调用getConnection()方法
            if (conn == null) {
                System.out.println("连接问题");
                return false;
            }
            boolean flag = false;
            PreparedStatement pst = null;
            try {
                pst = conn.prepareStatement(sql);
                pst.setString(1, msg.getUsername());
                pst.setString(2, msg.getPassword());
                flag = pst.executeUpdate() > 0;
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                colse(null, pst, conn);
            }
            return flag;
        }
    
        public static boolean login(Message msg) {
            String sql = "select * from user where user= ? and password= ?";
            Connection conn = getConnection();//调用getConnection()方法
            if (conn == null) {
                System.out.println("连接问题");
                return false;
            }
            PreparedStatement pst = null;
            ResultSet rs = null;
            boolean flag = false;
            try {
                pst = conn.prepareStatement(sql);
                pst.setString(1, msg.getUsername());
                pst.setString(2, msg.getPassword());
                rs = pst.executeQuery();
                flag = rs.next();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                colse(rs, pst, conn);
            }
            return flag;
        }
    }
    package QQ;
    
    public class main {
        public static void main(String[] args) {
    //        new QQReg().setVisible(true);
            new QQLogin().setVisible(true);
        }
    }
    package QQ;
    
    public class main2 {
        public static void main(String[] args) {
            new QQserver().start();
        }
    }
  • 相关阅读:
    poj 1904 King's Quest
    【BZOJ】1051: [HAOI2006]受欢迎的牛
    hdu 2767 Proving Equivalences
    hdu 3234 Exclusive-OR
    poj 1988 Cube Stacking
    poj 1733 Parity game
    hdu 3047 Zjnu Stadium 带权并查集
    poj 1182 食物链 种类并查集
    HDU 3749 Financial Crisis
    【BZOJ】1046 : [HAOI2007]上升序列
  • 原文地址:https://www.cnblogs.com/houtian2333/p/10702910.html
Copyright © 2020-2023  润新知