最小生成树动态演示

  1. 实验目的

  1. 掌握图的存储结构;

  2. 掌握利用C/C++编程语言实现数据结构的编程方法;

  3. 通过上机时间加强利用数据结构解决实际应用问题的能力;

  1. 实验相关知识

  1. 图的邻接存储结构实现;

  2. Prim算法求图的最小生成树;

  1. 实验内容与要求

  1. 利用EasyX绘制图。

  2. 利用Prim算法求图的最小生成树。

  1. 实现过程与结构

  1. 读取文件中图G的顶点信息和边信息,利用EasyX绘制图,并利用Prim算法求出图G的最小生成树,并突出显示。

输入说明:图信息文件 中所包含信息格式为

顶点个数n

n个顶点的坐标

边的条数m

m条边的起点,终点,权重

例如“graph4.txt”文件所示如下,其中红色字体为说明文字,非文档中的内容:

4 (4个顶点)

78 96

129 468

280 450

400 35

6 (6条无向边)

1 2 19 (<1,2> 权重为19)

1 3 23

1 4 30

2 3 17

2 4 13

3 4 12

运行结果说明:

读取图文件中的信息后,利用EasyX进行绘图,如下所示

最小生成树动态演示

可以通过鼠标左键拖拽顶点,移动顶点的位置,点击鼠标右键开始求解最小生成树,并突出显示该最小生成树,如下图所示。

最小生成树动态演示

 

  1. 代码框架与说明

#include <graphics.h>      // 引用图形库头文件
#include<string.h>
#include<math.h>
#include <stdio.h>
#include<string>
#include<fstream>
using namespace std;
int win_width = 640;
int win_height = 560;
int origin_x = 0;// 坐标原点位置x轴
int origin_y = 0;// 坐标原点位置y轴
int R = 20;
const int MAX_VERTEX_NUM = 20;
typedef struct Node
{
    int x;
    int y;
    int r = R;
}Node;
typedef struct
{
    Node vexs[MAX_VERTEX_NUM];    //顶点集     
    int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  //邻接矩阵,于无权图1、0表示两个顶点是否相邻,对于有权图为权值
    int vexnum, arcnum; //图的顶点数和弧数
}Graph;
Graph G;
typedef struct Closeedge
{
    int end_ver;
    int lowcost;
    int flag;
}Closeedge;
Closeedge closeedges[MAX_VERTEX_NUM];//最小生成树的边
void init();//初始化窗体
void init_Graph();
void draw_Graph();
void draw_arc(Node v1, Node v2, int weight);//在v1和v2顶点之间绘制一条直线,并在直线的中心出标注边的权重weight
void draw_vex(Node v, int i);//绘制第i个顶点v
void adjust_Grahp(MOUSEMSG m_down);//可以利用鼠标拖动圆,调整图中顶点的位置
void find_min_tree();// 求解最小生成树
void paint_min_tree();//绘制最小生成树 
int main()
{
    init();
    init_Graph();
    draw_Graph();
    MOUSEMSG m_down;//定义一个鼠标消息    
    while (1)
    {
        m_down = GetMouseMsg();
        if (m_down.uMsg == WM_LBUTTONDOWN)
        {
            adjust_Grahp(m_down);
        }
        if (m_down.uMsg == WM_RBUTTONDOWN)
        {
            break;
        }
    }
    find_min_tree();
    Sleep(100000);
    closegraph();
}
void init()//初始化窗口大小,窗口坐标中心点/画板背景
{
    initgraph(win_width, win_height);   // 创建绘图窗口,大小为 640x480 像素        
    setorigin(origin_x, origin_y);//设置绘图的中心点为窗体的中心点    
    setbkcolor(BLACK);
    cleardevice();//清理窗口
    return;
}
void init_Graph()
{
    int i, j;
    int v1, v2, weight;
    string filename = "../graph10.txt";
    ifstream infile(filename);
    infile >> G.vexnum;
    G.arcnum = 0;
    for (i = 1; i <= G.vexnum; i++)
    {
        infile >> G.vexs[i].x >> G.vexs[i].y;
    }
    for (i = 1; i <= G.vexnum; i++)
    {
        for (j = 1; j <= G.vexnum; j++)
        {
            G.arcs[i][j] = -1;
        }
        G.arcs[i][j] = 0;
    }
    infile >> G.arcnum;
    for (i = 1; i <= G.arcnum; i++)
    {
        infile >> v1 >> v2 >> weight;
        G.arcs[v1][v2] = weight;
        G.arcs[v2][v1] = weight;
    }
}
void draw_arc(Node v1, Node v2, int weight)//在v1和v2顶点之间绘制一条直线,并在直线的中心出标注边的权重weight
{
    line(v1.x, v1.y, v2.x, v2.y);
    TCHAR s[5];
    swprintf_s(s, _T("%d"), weight);
    settextcolor(WHITE);
    outtextxy((v1.x + v2.x) / 2, (v1.y + v2.y) / 2, s);
}
void draw_vex(Node v, int i)//绘制第i个顶点v
{
    fillcircle(v.x, v.y, v.r);
    TCHAR s[5];
    swprintf_s(s, _T("%d"), i);
    settextcolor(WHITE);
    outtextxy(v.x - R / 4, v.y - R / 4, s);
}
void draw_Graph()//绘制图
{
    setlinecolor(RED);
    for (int i = 1; i <= G.vexnum; i++)
    {
        for (int j = 1; j <= G.vexnum; j++)
        {
            draw_arc(G.vexs[i], G.vexs[j], G.arcs[i][j]);
        }
    }
    setfillcolor(MAGENTA);
    for (int i = 1; i <= G.vexnum; i++)
    {
        draw_vex(G.vexs[i], i);
    }
}
int get_clickcirclenum(double x, double y)//获取所点击圆的编号
{
    for (int i = 1; i <= G.vexnum; i++)
    {
        if ((G.vexs[i].x - x) * (G.vexs[i].x - x) + (G.vexs[i].y - y) * (G.vexs[i].y - y) <= G.vexs[i].r * G.vexs[i].r)
            return i;
    }
    return -1;
}
void adjust_Grahp(MOUSEMSG m_down)//可以利用鼠标拖动圆,调整图中顶点的位置
{
    MOUSEMSG m;//定义一个鼠标消息    
    int node_num;
    node_num = get_clickcirclenum(m_down.x, m_down.y);
    if (node_num > 0)
    {
        while (true)
        {
            m = GetMouseMsg();
            if (m.uMsg == WM_LBUTTONUP)
            {
                settextcolor(RED);
                G.vexs[node_num].x = G.vexs[node_num].x + (m.x - m_down.x);
                G.vexs[node_num].y = G.vexs[node_num].y + (m.y - m_down.y);
                cleardevice();
                draw_Graph();//重绘图
                break;
            }
        }
    }
    return;
}
void find_min_tree()// 求解最小生成树
{
    for (int i = 1; i <= G.vexnum; i++)
    {
        closeedges[i].end_ver = 1;
        closeedges[i].lowcost = G.arcs[1][i];
        closeedges[i].flag = 0;
    }
    closeedges[1].flag = 1;
    int min;
    for (int i = 2; i <= G.vexnum; i++)
    {
        min = -1;
        for (int j = 1; j <= G.vexnum; j++)
        {
            if (closeedges[j].flag == 0 && (closeedges[j].lowcost > 0 && (min < 0 || closeedges[min].lowcost>closeedges[j].lowcost)))
                min = j;
        }
        closeedges[min].flag = 1;
        setlinecolor(GREEN);
        setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 5);
        draw_arc(G.vexs[closeedges[min].end_ver], G.vexs[min], closeedges[min].lowcost);
        setlinecolor(RED);
        setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 1);
        setfillcolor(MAGENTA);
        for (int i = 1; i <= G.vexnum; i++)
        {
            draw_vex(G.vexs[i], i);
        }
        Sleep(1000);
        for (int j = 2; j <= G.vexnum; j++)
        {
            if (closeedges[j].flag == 0 && (G.arcs[j][min] > 0 && (closeedges[j].lowcost < 0 || closeedges[j].lowcost > G.arcs[j][min])))
            {
                closeedges[j].end_ver = min;
                closeedges[j].lowcost = G.arcs[j][min];
            }
        }
        getchar();
    }
}