地图着色问题课程设计

                         XXXX学院

 

                   工科课程设计 -《数据结构》

 

 

 

            题  目:       地图着色问题           

            学  号:  XXXXXX  

            姓  名:     XXX     

            班  级:            软件工程二班          

          指导教师:          XX老师            

            日  期:          201812月          

 

 

 

目录

1. 概述 1

1.1 目的 1

1.2 问题描述 1

1.3 运行环境 1

2. 总体设计 1

2.1界面设计 1

2.2算法设计 1

2.3数据结构设计 2

3. 详细设计 2

3.1界面详细设计 2

3.2数据结构设计 4

3.3算法设计内容 4

4. 实现情况和测试部分 5

4.1实现情况 5

4.2测试部分 6

5. 使用说明 6

5.1说明 6

6. 总结 6

 

 

 

 

 

 

 

 

 

 

 

 

 

  1. 概述
    1. 目的

对数据结构课程内容的复习,把所学知识应用到实际问题中去,提升自身思考能力和编码能力,为之后的学习打下基础。

 

    1. 问题描述

设计地图着色软件,对湖南省地图中的地级市进行着色,要求相邻地级市所使用的颜色不同,并保证使用的颜色最少。

 

1.3 运行环境

Jdk1.8

 

  1. 总体设计

2.1界面设计

运用JFrame类构造基本窗口,在窗口中显示绘图结果。

 

2.2算法设计

根据问题要求,可通过遍历所有节点来实现总体着色,也可将问题划分为多个小问题进行解决,可使用DFS递归来解决问题。又考虑到算法时间复杂度,在此用BFS解决,通过BFS遍历所有节点,判断节点是否被着色,如果被着色直接跳过,若没被着色就通过统计该节点的邻接节点颜色来推断该节点颜色,逐一涂色,问题解决。

 

2.3数据结构设计

运用队列来进行所有节点的储存,进行BFS之前,把一号节点先放入队列,在遍历一号节点的邻接节点是,把没有被着色的节点放入队列中,在把该节点标记为已着色。由于队列是一个先进先出的数据结构,所以才可在此问题中被使用。队列的数据结构正好符合着色问题中,优先遍历的需求。

 

  1. 详细设计

3.1界面详细设计

3.1.1界面图

初始界面图

点击”开始”按钮后界面图

 

 

3.1.2界面设计内容

使用JFrame类创建窗口,在窗口中添加JPanel画板,重写JLabel类MyLabel,在MyLabel类中添加标签中心点的Point属性,Point属性可以确定标签在何位置,重写JLabel的构造函数,使其更方便的构造标签内容和位置。通过重写JPanel类中的paintComponent()函数,在两个标签之间画线。

重写的JLabel的构造函数如下:

 

private Point center;//添加一个中心点坐标的成员变量
MyLabel(int x,int y,String name){//构造函数
    setName(name);
    setCenter(new Point(x + 50,y + 25));
    setBounds(x, y, 100, 50);
    setFont(new Font(null, Font.PLAIN, 20));
    setHorizontalAlignment(CENTER);
    setVerticalAlignment(CENTER);
    setOpaque(true);
    setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.BLACK));
}

重写的paintComponent()函数代码如下:

JPanel mapPanel = new JPanel(null){
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;//绘图类转为二维绘图类
        g2.setStroke(new BasicStroke(2.0f));//设置画笔
        for (int i=1;i<=13;i++){//通过循环寻找有路径的两个节点
            for(int j=1;j<=13;j++){
                if(mapLoad[i][j] == 1){
                    //画直线
                    DrawLine(g2, mapMember.get(i-1).getCenter(), mapMember.get(j-1).getCenter());
                }
            }
        }
    }
};

3.2数据结构设计

通过使用java类库中的Queue队列封装类作为主要数据结构,用链表实现该队列,构造该数据结构的方法为:

Queue<Integer>queue = new LinkedList<>();

节点和颜色则使用java类库中Vector向量封装类作为数据结构保存,构造该数据结构的方法为:

Vector<MyLabel> mapMember = new Vector<>();
Vector<Color> colors = new Vector<>();

路径则使用最基本的二维数组储存,由于数据不是太多,开15*15大小的二维数组即可,构造方法为:

mapLoad = new int[15][15];

以上就是最主要的几个数据结构。

 

3.3算法设计内容

在类中添加DrawColor()函数作为BFS算法接口,定义一个队列,把第一号节点放入队列中,通过一个循环判断该节点的邻接点是否有颜色,循环代码如下:

while(!queue.isEmpty()){//判断队列是否为空,非空则代表还有节点未被着色
    int colorRes = 100;//颜色代码
    int deal = queue.poll();//从队列中取出一个元素并从队列中删除该元素
    System.out.println(mapMember.get(deal-1).getName());
    int[] vis = new int[15];//记录邻接点有哪些颜色代码
    for(int i=1;i<=13;i++){//遍历所有节点
        if(mapLoad[deal][i] == 1){//如果i是该点的邻接点则记录颜色代码
            vis[color[i]]++;//颜色代码+1
            if(isQueue[i] == 0){//如果邻接点没有被着色则放入队列
                queue.offer(i);//放入队列
                isQueue[i] = 1;//标记为被着色
            }
        }
    }
    for(int i=1;i<=13;i++){//遍历所有颜色代码,取出一个没
        if(vis[i] == 0)     //有被使用过并且是最小的颜色代码
            colorRes = Integer.min(colorRes, i);
    }
    color[deal] = colorRes;//把该节点标记选出的最小颜色代码
    mapMember.get(deal-1).setBackground(colors.get(colorRes-1));//着色
}

此循环即可实现地图着色功能,并确保用最少的颜色。

  1. 实现情况和测试部分

4.1实现情况

基本着色功能已经实现,考虑到人机交互问题,是否应该增加选择省份等选项和着色动画。增加选择省份选项则要知道所有省份的地级市邻接表,工作量巨大。着色动画需要添加多线程以及更多java绘图编码知识,所以暂时还没有实现添加省份和着色动画等功能。

 

4.2测试部分

通过在BFS算法中输出遍历节点顺序:张家界市->常德市->怀化市->岳阳市->益阳市->邵阳市->娄底市->长沙市->永州市->衡阳市->湘潭市->株洲市->郴州市,以及笔算和查阅关于完全问题之一GCP问题之后可证实此算法符合问题内容要求。

 

  1. 使用说明

5.1说明

此程序采用傻瓜式操作模式,点击“开始”按钮即可运行程序并在界面框中看到结果。

 

  1. 总结

通过该课程设计让我加深了对队列和向量两个数据结构的认识,能够更加熟练的运用它们,对今后的编码有一定的帮助。

 

 

全部代码

1.Start类

import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;

import javax.swing.*;
import java.awt.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Vector;


public class Start {
    private static MyLabel zhangjiajie;
    private static MyLabel changde;
    private static MyLabel yueyang;
    private static MyLabel huaihua;
    private static MyLabel yiyang;
    private static MyLabel changsha;
    private static MyLabel shaoyang;
    private static MyLabel loudi;
    private static MyLabel xiangtan;
    private static MyLabel zhuzhou;
    private static MyLabel yongzhou;
    private static MyLabel hengyang;
    private static MyLabel chenzhou;
    private static int[][] mapLoad;
    private static Vector<MyLabel> mapMember;
    private static Vector<Color> colors;
    public static void main(String[] args) {
        try {
            BeautyEyeLNFHelper.frameBorderStyle = BeautyEyeLNFHelper.FrameBorderStyle.translucencyAppleLike;
            BeautyEyeLNFHelper.launchBeautyEyeLNF();
        } catch (Exception e) {
            e.printStackTrace();
        }

        JFrame frame = new JFrame("地图着色v1.0");
        frame.setLayout(null);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(400, 200, 1200, 825);
        frame.setVisible(true);



        JPanel panel = new JPanel(null);
        panel.setBounds(0, 0, 1200, 825);

        JButton button = new JButton("开始");
        button.setBounds(50, 25, 150, 50);

        /*13个地级市*/
        zhangjiajie = new MyLabel(110, 50, "张家界市");
        changde = new MyLabel( 320, 50, "常德市");
        yueyang = new MyLabel( 610, 80, "岳阳市");
        huaihua = new MyLabel( 80, 200, "怀化市");
        yiyang = new MyLabel(480, 160, "益阳市");
        changsha = new MyLabel( 820, 150, "长沙市");
        shaoyang = new MyLabel( 200, 340, "邵阳市");
        loudi = new MyLabel( 350, 260, "娄底市");
        xiangtan = new MyLabel( 600, 340, "湘潭市");
        zhuzhou = new MyLabel(800, 390, "株洲市");
        yongzhou = new MyLabel( 220, 490, "永州市");
        hengyang = new MyLabel( 470, 410, "衡阳市");
        chenzhou = new MyLabel( 600, 510, "郴州市");

        InitMapMessage();

        /*连线*/
        JPanel mapPanel = new JPanel(null){
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;//绘图类转为二维绘图类
                g2.setStroke(new BasicStroke(2.0f));//设置画笔
                for (int i=1;i<=13;i++){//通过循环寻找有路径的两个节点
                    for(int j=1;j<=13;j++){
                        if(mapLoad[i][j] == 1){
                            //画直线
                            DrawLine(g2, mapMember.get(i-1).getCenter(), mapMember.get(j-1).getCenter());
                        }
                    }
                }
            }
        };
        mapPanel.setBounds(50, 100, 1050, 600);
        mapPanel.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.BLACK));

        button.addActionListener(e -> {
            DrawColor();
        });

        mapPanel.add(zhangjiajie);
        mapPanel.add(changde);
        mapPanel.add(yueyang);
        mapPanel.add(changsha);
        mapPanel.add(huaihua);
        mapPanel.add(yiyang);
        mapPanel.add(shaoyang);
        mapPanel.add(loudi);
        mapPanel.add(xiangtan);
        mapPanel.add(zhuzhou);
        mapPanel.add(yongzhou);
        mapPanel.add(hengyang);
        mapPanel.add(chenzhou);

        panel.add(button);
        frame.add(mapPanel);
        frame.add(panel);
    }
    private static void DrawLine(Graphics2D g2,Point p1,Point p2){
        g2.drawLine(p1.x, p1.y, p2.x, p2.y);
    }
    private static void InitMapMessage(){
        colors = new Vector<>();
        colors.add(Color.RED);
        colors.add(Color.GREEN);
        colors.add(Color.YELLOW);
        colors.add(Color.CYAN);
        mapMember = new Vector<>();
        mapMember.add(zhangjiajie);
        mapMember.add(changde);
        mapMember.add(yueyang);
        mapMember.add(huaihua);
        mapMember.add(yiyang);
        mapMember.add(changsha);
        mapMember.add(shaoyang);
        mapMember.add(loudi);
        mapMember.add(xiangtan);
        mapMember.add(zhuzhou);
        mapMember.add(yongzhou);
        mapMember.add(hengyang);
        mapMember.add(chenzhou);
        mapLoad = new int[15][15];
        mapLoad[1][2] = mapLoad[2][1] = 1;
        mapLoad[1][4] = mapLoad[4][1] = 1;
        mapLoad[2][4] = mapLoad[4][2] = 1;
        mapLoad[2][3] = mapLoad[3][2] = 1;
        mapLoad[2][5] = mapLoad[5][2] = 1;
        mapLoad[3][5] = mapLoad[5][3] = 1;
        mapLoad[3][6] = mapLoad[6][3] = 1;
        mapLoad[4][5] = mapLoad[5][4] = 1;
        mapLoad[5][6] = mapLoad[6][5] = 1;
        mapLoad[4][7] = mapLoad[7][4] = 1;
        mapLoad[4][8] = mapLoad[8][4] = 1;
        mapLoad[5][8] = mapLoad[8][5] = 1;
        mapLoad[6][8] = mapLoad[8][6] = 1;
        mapLoad[8][9] = mapLoad[9][8] = 1;
        mapLoad[6][9] = mapLoad[9][6] = 1;
        mapLoad[6][10] = mapLoad[10][6] = 1;
        mapLoad[9][10] = mapLoad[10][9] = 1;
        mapLoad[7][8] = mapLoad[8][7] = 1;
        mapLoad[8][12] = mapLoad[12][8] = 1;
        mapLoad[9][12] = mapLoad[12][9] = 1;
        mapLoad[10][12] = mapLoad[12][10] = 1;
        mapLoad[10][13] = mapLoad[13][10] = 1;
        mapLoad[7][12] = mapLoad[12][7] = 1;
        mapLoad[7][11] = mapLoad[11][7] = 1;
        mapLoad[11][12] = mapLoad[12][11] = 1;
        mapLoad[11][13] = mapLoad[13][11] = 1;
        mapLoad[12][13] = mapLoad[13][12] = 1;
    }
    @SuppressWarnings("ConstantConditions")
    private static void DrawColor(){
        Queue<Integer>queue = new LinkedList<>();
        int[] isQueue = new int[15];
        int[] color = new int[15];
        queue.offer(1);
        isQueue[1] = 1;
        while(!queue.isEmpty()){//判断队列是否为空,非空则代表还有节点未被着色
            int colorRes = 100;//颜色代码
            int deal = queue.poll();//从队列中取出一个元素并从队列中删除该元素
            System.out.println(mapMember.get(deal-1).getName());
            int[] vis = new int[15];//记录邻接点有哪些颜色代码
            for(int i=1;i<=13;i++){//遍历所有节点
                if(mapLoad[deal][i] == 1){//如果i是该点的邻接点则记录颜色代码
                    vis[color[i]]++;//颜色代码+1
                    if(isQueue[i] == 0){//如果邻接点没有被着色则放入队列
                        queue.offer(i);//放入队列
                        isQueue[i] = 1;//标记为被着色
                    }
                }
            }
            for(int i=1;i<=13;i++){//遍历所有颜色代码,取出一个没
                if(vis[i] == 0)     //有被使用过并且是最小的颜色代码
                    colorRes = Integer.min(colorRes, i);
            }
            color[deal] = colorRes;//把该节点标记选出的最小颜色代码
            mapMember.get(deal-1).setBackground(colors.get(colorRes-1));//着色
        }
    }
}

           2.MyLabel类


import javax.swing.*;
import java.awt.*;

public class MyLabel extends JLabel {
    private Point center;//添加一个中心点坐标的成员变量
    MyLabel(int x,int y,String name){//构造函数
        setName(name);
        setCenter(new Point(x + 50,y + 25));
        setBounds(x, y, 100, 50);
        setFont(new Font(null, Font.PLAIN, 20));
        setHorizontalAlignment(CENTER);
        setVerticalAlignment(CENTER);
        setOpaque(true);
        setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.BLACK));
    }

    public Point getCenter() {
        return center;
    }

    private void setCenter(Point center) {
        this.center = center;
    }

}


 

  • 8
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值