图的基本操作及应用

题目一: 图的遍历

[问题描述]
  对给定图,实现图的深度优先遍历和广度优先遍历。
[基本要求]
   以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。
【测试数据】
  由学生依据软件工程的测试技术自己确定。
输入样例:

4 4
0 1 2 3
0 1
0 2
0 3
2 3

输出样例:

输出邻接表:
0:3 2 1
1:0
2:3 0
3:2 0
Depth first search:
输入开始节点:2
2301
Breadth first search:
输入开始节点:3
3201

CODE:

#include <iostream>
#include <cstring>
using namespace std;
const int MX=100;
int visit[MX];  //标记是否被遍历过
typedef struct arcnode
{
    int adjvex;  //每链表中所保存的信息,代表与头节点所连的节点的编号
    struct arcnode *next;  //指向下一个结点
} arcnode;
typedef struct vnode
{
    int data;  //每个链表中的头节点信息;图中每个节点的信息
    arcnode *firstarc;
} vnode,adjlist[MX];
typedef struct
{
    adjlist vertices;  //头节点数组
    int vexnum,arcnum;  //节点个数、边的个数
} algraph;
void creatudg(algraph &g)  //创建图
{
    cin>>g.vexnum>>g.arcnum;  //输入节点个数、边的个数
    int i,j;
    int v1,v2,n,m;
    for(i=0; i<g.vexnum; i++)  //输入图中的节点信息
    {
        cin>>n;
        g.vertices[i].data=n;
        g.vertices[i].firstarc=NULL;
    }
    for(i=0; i<g.arcnum; i++)
    {
        cin>>v1>>v2;  //输入一条边
        n=m=-1;
        for(j=0; j<g.vexnum; j++)  //在图中寻找这两个结点,因为是无向图所以要两个都要找
        {
            if(g.vertices[j].data==v1)
                n=j;
            if(g.vertices[j].data==v2)
                m=j;
            if(n!=-1&&m!=-1)
                break;
        }
        //采用头插法将两个编号保存在链表内
        arcnode *p1=new arcnode;
        p1->adjvex=m;
        p1->next=g.vertices[n].firstarc;
        g.vertices[n].firstarc=p1;
        arcnode *p2=new arcnode;
        p2->adjvex=n;
        p2->next=g.vertices[m].firstarc;
        g.vertices[m].firstarc=p2;
    }
}
void out(algraph g)  //输出邻接表
{
    int i;
    for(i=0; i<g.vexnum; i++)
    {
        cout<<g.vertices[i].data<<":";
        while(g.vertices[i].firstarc!=NULL)
        {
            cout<<g.vertices[i].firstarc->adjvex<<" ";  //只是输出了该节点所连的编号
            g.vertices[i].firstarc=g.vertices[i].firstarc->next;
        }
        cout<<endl;
    }
}
void dfs(algraph g,int v)
{
    cout<<v;  //v为结点数据
    int i;
    for(i=0;i<g.vexnum;i++)  //在数组里找到该节点,并标记该节点
    {
        if(g.vertices[i].data==v)
        {
            visit[i]=1;
            break;
        }
    }
    while(g.vertices[i].firstarc!=NULL)  //将该链表遍历完
    {
        if(visit[g.vertices[i].firstarc->adjvex])  //如果已被标记则指向下一个
        {
            g.vertices[i].firstarc=g.vertices[i].firstarc->next;
        }
        else
        {
            dfs(g,g.vertices[g.vertices[i].firstarc->adjvex].data);  //若未被标记则遍历代表该节点的链表
        }
    }
}
//队列
typedef struct QNode
{
    int base;
    struct QNode *next;
} QNode,*QueuePtr;
typedef struct
{
    QueuePtr f,r;
} LinkQueue;
void InitQueue(LinkQueue &q)
{
    q.f=q.r=new QNode;
    q.f->next=NULL;
    return;
}
void Qpush(LinkQueue &q,int t)
{
    QueuePtr p;
    p=new QNode;
    p->base=t;
    p->next=NULL;
    q.r->next=p;
    q.r=p;
    return;
}
bool Empty(LinkQueue q)
{
    return q.f==q.r;
}
void Qpop(LinkQueue &q)
{
    if(!Empty(q))
        q.f=q.f->next;
}
void bfs(LinkQueue &q,algraph g,int v)
{
    Qpush(q,v);
    while(!Empty(q))  //结束条件为队列为空
    {
        int n=q.f->next->base;
        cout<<n;
        int i;
        for(i=0;i<g.vexnum;i++)  //在数组中寻找该该节点的编号,并标记
        {
            if(g.vertices[i].data==n)
            {
                visit[i]=0;
                break;
            }
        }
        while(g.vertices[i].firstarc!=NULL)  //将该链表中未被标记的全部进队列,进队列后标记
        {
            if(visit[g.vertices[i].firstarc->adjvex])
            {
                visit[g.vertices[i].firstarc->adjvex]=0;
                Qpush(q,g.vertices[g.vertices[i].firstarc->adjvex].data);
            }
            g.vertices[i].firstarc=g.vertices[i].firstarc->next;
        }
        Qpop(q);
    }
}
int main()
{
    memset(visit,0,sizeof(visit));  //记录被标记过的结点
    algraph g;
    creatudg(g);  //创建图
    cout<<"输出邻接表:"<<endl;
    out(g);
    int v;
    cout<<"Depth first search:"<<endl;
    memset(visit,0,sizeof(visit));
    cout<<"输入开始节点:";
    cin>>v;
    dfs(g,v);
    cout<<endl;
    cout<<"Breadth first search:"<<endl;
    cout<<"输入开始节点:";
    cin>>v;
    LinkQueue q;
    InitQueue(q);
    bfs(q,g,v);
    return 0;
}
/*
4 4
1 2 3 4
4 1
4 2
4 3
2 3
4 5
7 5 6 9
7 9
7 6
7 5
5 6
5 9
*/

题目二:最小生成树问题

[问题描述]
若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
[基本要求]
1.利用克鲁斯卡尔算法求网的最小生成树。
2.要求输出各条边及它们的权值。
[实现提示]
通信线路一旦建成,必然是双向的。因此,构造最小生成树的网一定是无向网。设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数。
图的存储结构的选取应和所作操作相适应。为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组表示图。
[测试数据]
由学生依据软件工程的测试技术自己确定。
输入样例:

7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11

输出样例:

最小生成树为:
0 3 5
2 4 5
3 5 6
5 1 7
1 4 7
4 6 9

CODE:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

int parent[30];
struct Edge
{
    int id;
    int s;
    int e;
    int w;
} edge[30];
bool cmp(Edge a,Edge b)
{
    if(a.w==b.w)
        return a.id<b.id;
    return a.w<b.w;
}
int find(int x)
{
    if(parent[x]!=x)
        return parent[x]=find(parent[x]);
    return x;
}
int main()
{
    int n,m,k,g;
    cin>>m;
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>edge[i].s>>edge[i].e>>edge[i].w;
        edge[i].id=i;
    }
    sort(edge,edge+n,cmp);
    for(int i=0; i<n; i++)
        parent[i]=i;
    cout<<"最小生成树为:"<<endl;
    for(int i=0; i<n; i++)
    {
        k=find(edge[i].s);
        g=find(edge[i].e);
        if(k!=g)
        {
            parent[find(k)]=find(g);
            cout<<k<<" "<<g<<" "<<edge[i].w<<endl;
        }
    }
    cout<<endl<<endl;
    return 0;
}

题目三:拓扑排序的应用

试编程,为某校计算机科学与技术专业的四年全部课程做一个排课方案。

[测试数据]
自行设计
样例输入:

7 7
a b c d e f g
a g
g f
f e
b c
b d
c d
c e

样例输出:

输出邻接表:
a 0:g
b 0:d c
c 1:e d
d 2:
e 2:
f 1:e
g 1:f
bcdagfe

CODE:

#include <iostream>
#include <cstring>
using namespace std;
const int MX=100;
int visit[MX];
int indegree[MX];
typedef struct arcnode
{
    char adjvex;
    struct arcnode *next;
} arcnode;
typedef struct vnode
{
    char data;
    arcnode *firstarc;
} vnode,adjlist[MX];
typedef struct
{
    adjlist vertices;
    int vexnum,arcnum;
} algraph;
void creatudg(algraph &g)
{
    cin>>g.vexnum>>g.arcnum;
    int i,j;
    int n,m;
    char ch,v1,v2;
    for(i=0; i<g.vexnum; i++)
    {
        cin>>ch;
        g.vertices[i].data=ch;
        g.vertices[i].firstarc=NULL;
    }
    for(i=0; i<g.arcnum; i++)
    {
        cin>>v1>>v2;
        n=m=-1;
        for(j=0; j<g.vexnum; j++)
        {
            if(g.vertices[j].data==v1)
                n=j;
            if(g.vertices[j].data==v2)
                m=j;
            if(n!=-1&&m!=-1)
                break;
        }
        arcnode *p1=new arcnode;
        p1->adjvex=g.vertices[m].data;
        p1->next=g.vertices[n].firstarc;
        g.vertices[n].firstarc=p1;
        indegree[m]++;
    }
}
void out(algraph g)
{
    int i;
    for(i=0; i<g.arcnum; i++)
    {
        cout<<g.vertices[i].data<<" "<<indegree[i]<<":";
        while(g.vertices[i].firstarc!=NULL)
        {
            cout<<g.vertices[i].firstarc->adjvex<<" ";
            g.vertices[i].firstarc=g.vertices[i].firstarc->next;
        }
        cout<<endl;
    }
}
typedef struct
{
    char *base;
    char *top;
    int l;
} SqStack;
void InitStack(SqStack &s)
{
    s.base=new char[MX];
    s.top=s.base;
    s.l=MX;
    return;
}
void Push(SqStack &s,char ch)
{
    if(s.top-s.base==s.l)
        return;
    *s.top++=ch;
    return;
}
bool Empty(SqStack &s)
{
    return s.base==s.top;
}
int find(algraph &g,char ch)
{
    int i;
    for(i=0; i<g.vexnum; i++)
    {
        if(g.vertices[i].data==ch)
            break;
    }
    return i;
}
void topol(algraph &g)
{
    SqStack s;
    InitStack(s);
    int i;
    for(i=0; i<g.vexnum; i++)
    {
        if(indegree[i]==0)
        {
            Push(s,g.vertices[i].data);
            visit[i]=1;
        }
    }
    while(!Empty(s))
    {
        cout<<*(s.top-1);
        int n=find(g,*(s.top-1));
        s.top--;
        visit[n]=1;
        while(g.vertices[n].firstarc!=NULL)
        {
            indegree[find(g,g.vertices[n].firstarc->adjvex)]--;
            g.vertices[n].firstarc=g.vertices[n].firstarc->next;
        }
        for(i=0; i<g.vexnum; i++)
        {
            if(visit[i]==0&&indegree[i]==0)
            {
                Push(s,g.vertices[i].data);
                visit[i]=1;
            }
        }
    }
}
int main()
{
    int visit[MX];
    memset(visit,0,sizeof(visit));
    memset(indegree,0,sizeof(indegree));
    algraph g;
    creatudg(g);
    cout<<"Êä³öÁÚ½Ó±í:"<<endl;
    out(g);
    topol(g);
    cout<<endl;
    return 0;
}

题目四:最短路径问题

[问题描述]
给定一个无向网,可以求得任意一对顶点之间的最短路径。
[基本要求]
以邻接矩阵为存储结构,实现弗洛伊德算法求解每一对顶点之间的最短路径及最短路径长度。
[测试数据]
由学生依据软件工程的测试技术自己确定。
样例输入:

4 8
1 3 2
1 2 9
2 1 5
2 3 8
2 0 3
3 2 6
0 1 1
0 3 4

样例输出:

输入两端点:3 0
最短路径长度:9
路径是:320
1 3
最短路径长度:2
路径是:13
-1 -1

弗洛伊德算法
CODE:

#include <iostream>
#include <cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int MX=100;
int d[MX][MX];
int path[MX][MX];
typedef struct
{
    int arcs[MX][MX];
    int vexnum,arcnum;
} amgraph;
void createudn(amgraph &g)
{
    cin>>g.vexnum>>g.arcnum;
    int i,j,k,v1,v2,w;
    for(i=0; i<g.vexnum; i++)
    {
        for(j=0; j<g.vexnum; j++)
        {
            if(i==j)
                g.arcs[i][j]=0;
            else
                g.arcs[i][j]=INF;
        }
    }
    for(k=0; k<g.arcnum; k++)
    {
        cin>>v1>>v2>>w;
        g.arcs[v1][v2]=w;
    }
}
void shortestpath(amgraph &g)
{
    int i,j,k;
    for(i=0; i<g.vexnum; i++)
        for(j=0; j<g.vexnum; j++)
        {
            d[i][j]=g.arcs[i][j];
            if(d[i][j]<INF&&i!=j)
                path[i][j]=i;
            else
                path[i][j]=-1;
        }
    for(k=0; k<g.vexnum; k++)
        for(i=0; i<g.vexnum; i++)
            for(j=0; j<g.vexnum; j++)
            {
                if((d[i][k]+d[k][j])<d[i][j])
                {
                    d[i][j]=d[i][k]+d[k][j];
                    path[i][j]=path[k][j];
                }
            }
}
typedef struct
{
    int *base;
    int *top;
    int l;
} SqStack;
void InitStack(SqStack &s)
{
    s.base=new int[MX];
    s.top=s.base;
    s.l=MX;
    return;
}
void Push(SqStack &s,int ch)
{
    if(s.top-s.base==s.l)
        return;
    *s.top++=ch;
    return;
}
void Pop(SqStack &s)
{
    s.top--;
}
bool Empth(SqStack &s)
{
    return s.base==s.top;
}
void Path(int n,int m)
{
    cout<<"路径是:";
    SqStack s;
    InitStack(s);
    Push(s,m);
    while(n!=m)
    {
        m=path[n][m];
        Push(s,m);
    }
    while(!Empth(s))
    {
        cout<<*(s.top-1);
        Pop(s);
    }
}
int main()
{
    amgraph g;
    createudn(g);
    shortestpath(g);
    cout<<"输入两端点:";
    int n,m;
    while(cin>>n>>m)
    {
        if(n==-1&&m==-1)
            break;
        cout<<"最短路径长度:"<<d[n][m]<<endl;
        Path(n,m);
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44350170/article/details/103186827