3 Prim算法的设计--来源舒姐

abyssfall的博客_CSDN博客-计科学子的头发账本,代码存档领域博主

作者: 冯向阳时间限制: 1S章节: 课程设计

问题描述 :

在使用图的邻接矩阵ADT的基础上,设计能指定起始结点u的Prim算法,用以求无向网的最小生成树,并以文本形式输出生成树中各条边以及它们的权值。将此算法加入到邻接矩阵ADT中,在邻接矩阵ADT中提供一个公有的成员函数Prim(u, adjvex, lowcost)。

提示:

(1)Prim算法的基本思想是从结点的角度出发。初始时,生成树中一个结点也没有,然后将一个个结点加入生成树,直到所有的结点都被加入,生成树就形成了。具体来讲,Prim算法由以下几个步骤组成:

1)初始时,生成树的结点集U为空;

2)随意选择一个结点,加入结点集V,然后重复下列工作,直到U=V;

3)把(u,v)加入生成树的边集,v加入到U。

(2)在Prim算法的执行过程中,需要保存哪些结点在U中,哪些结点不在U中的信息。这可以用一个布尔型的一维数组flag来保存。如果结点i已在生成树中,则flag[i]的值为true,否则为false。

(3)在Prim算法的执行过程中,还需要保存U中的结点到V-U中结点的权值最小的边,这可以用2个一维数组lowcost和adjvex来记录。lowcost[i]表示U中的结点到结点i的所有边中的最小权值。adjvex[i]表示从U中的哪一个结点出发到结点i的权值是最小的。

参考函数原型:

template<class TypeOfVer, class TypeOfEdge>

bool adjmatrix_graph<TypeOfVer, TypeOfEdge>::Prim(int u, int adjvex[], TypeOfEdge lowcost[]);

输入说明 :

第一行:图的类型

第二行:结点数

第三行:结点集

第四行:无边标记

第五行:边数

第六行:边集

第七行:权集

第八行:起始结点序号u

输出说明 :

第一行:图的类型

第二行:顶点集

     空行

第三行:邻接矩阵(列与列之间用格式控制符'\t'分隔)

第四行:各条边以及它们的权值,输出格式为:

(c,b,5),(d,c,3),(e,d,8),(a,e,14),(d,f,21),(e,g,16)

其中,每个括号内的信息为一条边,格式为(邻接点, 自己, 权值),边的输出顺序为按照(自己这个)点的编号顺序输出。“自己这个”不包括起始点,比如范例中输出的边不包括起始点a,也就是没有(*,a,*)。

UDN
7
a b c d e f g
9999
11
0 1
0 4
0 6
1 2
1 3
1 4
2 3
3 4
3 5
4 6
5 6
19 14 18 5 7 12 3 8 21 16 27
0

UDN
a b c d e f g

9999    19    9999    9999    14    9999    18    
19    9999    5    7    12    9999    9999    
9999    5    9999    3    9999    9999    9999    
9999    7    3    9999    8    21    9999    
14    12    9999    8    9999    9999    16    
9999    9999    9999    21    9999    9999    27    
18    9999    9999    9999    16    27    9999    
(c,b,5),(d,c,3),(e,d,8),(a,e,14),(d,f,21),(e,g,16)

#include <bits/stdc++.h>
using namespace std;

const int MAX = 1000;

string kind;
int m = 0;
int arr[MAX][2] = {0}; //输入权集的对应横纵坐标
int none, u;           //无边标记
int all[MAX][MAX] = {0};
bool tree_flag[MAX][MAX] = {false};

struct E //边
{
    int num;
    int weight;
    E *next = NULL;
};

struct V //结点
{
    string data;
    E *next = NULL;
};

struct graph
{
    V m[MAX];
    int number_of_V;
    int number_of_E;
};

void addweight_no_direction(graph &g);
void addweight(graph &g);

void creat_no_directioin(graph &g)
{
    int v, f;

    cin >> v;
    g.number_of_V = v;
    for (int i = 0; i < v; i++)
    {
        cin >> g.m[i].data;
    }
    //输入顶点字母

    cin >> none; //输入无边标记

    cin >> f;
    g.number_of_E = f;
    for (int i = 0; i < f; i++)
    {
        int v1, v2;
        cin >> v1 >> v2;
        arr[i][0] = v1;
        arr[i][1] = v2;

        E *p1 = new E;
        p1->num = v2;
        p1->next = g.m[v1].next;
        g.m[v1].next = p1;

        E *p2 = new E;
        p2->num = v1;
        p2->next = g.m[v2].next;
        g.m[v2].next = p2;
    }
    addweight_no_direction(g);
}
void addweight_no_direction(graph &g)
{
    for (int j = 0; j < g.number_of_E; j++)
    {
        int temp = 0;
        cin >> temp;
        int number1 = arr[j][0];
        int number2 = arr[j][1];

        all[number1][number2] = temp;
        all[number2][number1] = temp;

        E *p;
        E *p1;
        p = g.m[number1].next;
        p1 = g.m[number2].next;
        while (p)
        {
            if (p->num == number2)
            {
                p->weight = temp;
            }
            p = p->next;
        }

        while (p1)
        {
            if (p1->num == number1)
            {
                p1->weight = temp;
            }
            p1 = p1->next;
        }
    }
}

void creat_direction(graph &g)
{
    int v;
    int f;

    cin >> v;
    g.number_of_V = v;
    for (int i = 0; i < v; i++)
    {
        cin >> g.m[i].data;
    } //输入顶点字母

    cin >> none; //输入无边标记

    cin >> f;
    g.number_of_E = f;
    for (int i = 0; i < f; i++)
    {
        int v1, v2;
        cin >> v1 >> v2;
        arr[i][0] = v1;
        arr[i][1] = v2;
        E *p1 = new E;
        p1->num = v2;
        p1->next = g.m[v1].next;
        g.m[v1].next = p1;
    }

    addweight(g);
}

void addweight(graph &g)
{
    for (int j = 0; j < g.number_of_E; j++)
    {
        int temp = 0;
        cin >> temp;
        int number1 = arr[j][0];
        int number2 = arr[j][1];

        all[number1][number2] = temp;

        E *p;
        p = g.m[number1].next;

        while (p)
        {
            if (p->num == number2)
            {
                p->weight = temp;
            }
            p = p->next;
        }
    }
}

void printV(graph g)
{
    int m = 0;
    for (int h = 0; h < g.number_of_V; h++)
    {
        if (m == 1)
        {
            cout << " ";
        }
        m = 1;
        cout << g.m[h].data;
    }
    cout << endl
         << endl;
}

void printgraph(graph g)
{
    for (int i = 0; i < g.number_of_V; i++)
    {
        for (int j = 0; j < g.number_of_V; j++)
        {
            if (all[i][j] == 0)
            {
                cout << none;
            }

            else
            {
                cout << all[i][j];
            }
            cout << '\t';
        }
        cout << endl;
    }
}

void print_tree(graph g)
{
    bool f = false;
    for (int i = 0; i < g.number_of_V; i++)
    {
        if (i == u)
        {
            continue; //根节点不输出
        }
        for (int j = 0; j < g.number_of_V; j++)
        {
            if (tree_flag[i][j] == true)
            {
                if(f == true)
                {
                    cout<<",";
                }
                else
                {
                    f = true;
                }
                cout << "(" << g.m[j].data << "," << g.m[i].data << "," << all[i][j] << ")";
            }
        }
    }
}

int find(graph g, string data)
{
    for (int i = 0; i < g.number_of_V; i++)
    {
        if (g.m[i].data == data)
        {
            return i;
        }
    }

    return -1;
}

void prim(graph g, int u)
//核心思路:划分已添加和未添加两部分,
{
    bool flag_judge[g.number_of_V] = {false};
    //标记已添加至二叉树的结点,每个点都要被添加且仅添加一次,以true的结点遍历寻找指向false结点的最小边
    //int flag_num[g.number_of_V] = {0};
    //标记已添加结点的已连接边,一旦到2,不再加边;结束后为0,视为叶子结点

    int now_node = 1; //记录一下循环结束条件

    vector<V> now_tree;
    now_tree.push_back(g.m[u]);
    flag_judge[u] = true; //从这里开始

    while (now_node < g.number_of_V) //还有节点没有被加入二叉树
    {
        int start_node = -1, min_node = -1, min_value = none;
        for (int i = 0; i < now_node; i++)
        {
            //注意一下这里 是不是把nowtree的编号和g的编号弄混了
            //if (flag_num[find(g, now_tree[i].data)] == 2)
            //{
            //    continue;
            //} //这个结点已经到达构建二叉树的上限了
            //最小生成树不用限死在二叉树啊!!!!!!!!!啊!!!!!!!

            E *p = now_tree[i].next;
            while (p != NULL)
            {
                if (p->weight < min_value && flag_judge[p->num] == false) //比现在的边小,且终点未被加入
                {
                    min_value = p->weight;
                    min_node = p->num;
                    start_node = i;
                }
                p = p->next;
            }
        } //找出指向未加入结点的最小边

        start_node = find(g, now_tree[start_node].data);

        flag_judge[min_node] = true;

        //flag_num[start_node]++;

        tree_flag[min_node][start_node] = true;

        //标记该条边和该点入选
        now_tree.push_back(g.m[min_node]);
        now_node++;
    }
}

int main()
{
    cin >> kind;
    if (kind == "DN")
    {
        cout << "DN" << endl;
        graph g;
        creat_direction(g);
        printV(g);

        printgraph(g);

        cin >> u;
        prim(g, u);

        print_tree(g);
    }

    else if (kind == "UDN")
    {
        cout << "UDN" << endl;
        graph g;
        creat_no_directioin(g);
        printV(g);

        printgraph(g);

        cin >> u;
        prim(g, u);

        print_tree(g);
    }

    getchar();
    getchar();

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨骅麟(Patrick Young)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值