编程题实训-图

第2关:基于Dijsktra算法的最短路径求解

任务描述
一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知。给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间的最短路径。

编程要求
输入
多组数据,每组数据有m+3行。第一行为两个整数n和m,分别代表城市个数n和路径条数m。第二行有n个字符,代表每个城市的名字。第三行到第m+2行每行有两个字符a和b和一个整数d,代表从城市a到城市b有一条距离为d的路。最后一行为两个字符,代表待求最短路径的城市起点和终点。当n和m都等于0时,输入结束。

输出
每组数据输出两行。第一行为一个整数,为从起点到终点之间最短路的长度。第二行为一串字符串,代表该路径。每两个字符之间用空格隔开。

测试说明
平台会对你编写的代码进行测试:

测试输入:
3 3
A B C
A B 1
B C 1
A C 3
A C
6 8
A B C D E F
A F 100
A E 30
A C 10
B C 5
C D 50
E D 20
E F 60
D F 10
A F
0 0

预期输出:
2
A B C
60
A E D F

#include<iostream>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MaxInt 32767                        //最大值
#define MVNum 100                           //最大数量
using namespace std;
int D[MVNum];           //D[i]记录从源到终端的当前最短
int Path[MVNum];        //路径[i]记录是从源到终端上vi的当前最小序列号
typedef struct
{
    char vexs[MVNum];                   //点列表
    int arcs[MVNum][MVNum];               //连接到短端口阵列
    int vexnum;                           //数字总数
    int arcnum;                        //图中GL的总数
} AMGraph;
int LocateVex(AMGraph G,char u)
{//存储在“返回”表中的标签,无论是否返回
    int i;
    for(i=0;i<G.vexnum;i++)
        if(u==G.vexs[i])
            return i;
    return ERROR;
}
char OrigialVex(AMGraph G,int u)
{//以下文件u的元素作为表存储在返回表中?
    return G.vexs[u];
}
int CreateDN(AMGraph &G,int spot,int edge)
{//使用连接LPG阵列的方法创建定向屏蔽
    G.vexnum=spot;
    G.arcnum=edge;
    int i,j,k,w;
    char v1,v2;
    for(i=0;i<G.vexnum;++i)
        cin>>G.vexs[i];       //输入
    for(i=0;i<G.vexnum;++i) 
        for(j=0;j<G.vexnum;++j)
            G.arcs[i][j]=MaxInt;
    for(k=0;k<G.arcnum;++k)                     
    {
        cin>>v1>>v2>>w;       ///输入附着到第一个面板的标签
        i=LocateVex(G, v1);
        j=LocateVex(G, v2);  //确定v1和2之间的位置
        G.arcs[i][j]=w;    
    }//for
    return OK;
}
void ShortestPath_DIJ(AMGraph G, char V)
{//用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径
/**************begin************/
int v, w, i, min;
    bool final[MVNum]; //final[w] = true表示已经找到从v到w的最短路径
    v = LocateVex(G, V);

    for (i = 0; i < G.vexnum; ++i)
    {
        final[i] = false; //所有的点开始时都是未知最短路径的
        D[i] = G.arcs[v][i]; //将与v点有连线的点加上权值
        if (D[i] < MaxInt) //如果i点与v点本身连通,那么将从v点到i点的最短路径设置成i点
            Path[i] = v;
        else
            Path[i] = -1;
    }

    D[v] = 0;
    final[v] = true; //对源点进行初始化

    for (i = 1; i < G.vexnum; ++i) //其余G.vexnum-1个顶点
    {
        min = MaxInt; //当前所知离v顶点的最近距离
        for (w = 0; w < G.vexnum; ++w)
            if (!final[w] && D[w] < min)
            {
                v = w;
                min = D[w]; //w顶点离v顶点更近
            }
        final[v] = true; //离v顶点最近的v加入S集
        for (w = 0; w < G.vexnum; ++w) //更新当前最短路径及距离
            if (!final[w] && (min + G.arcs[v][w] < D[w]))
            {
                D[w] = min + G.arcs[v][w];
                Path[w] = v;
            }
    }


    /**************end************/
}
void Find(AMGraph G,int v)
{//在路径编号组中查找程序编号
    if(Path[v]==-1)    
        return ;
    else
    {
        Find(G,Path[v]);   
        cout<<OrigialVex(G,Path[v])<<" ";   //输出点列表中标记有路径[v]的元素
    }
}
int main()
{
    char a,b;      
    int n,m;     
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        AMGraph G;
        CreateDN(G,n,m);          //创建定向屏蔽
        cin>>a;                 //输入
        ShortestPath_DIJ(G,a);  //如果G的接触点和它的静止点之间有一段短时间
        cin>>b;            //触点底座b
        int v=LocateVex(G,b);//返回地面表中的下一个标记,以验证测量值的数量
        cout<<D[v]<<endl;      //将它们之间的短距离输出到B
        Find(G,v);
        cout<<b<<endl;
    }
    return 0;
}

第3关:六度空间理论

任务描述
“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。

编程要求
输入
多组数据,每组数据m+1行。第一行有两个数字n和m,代表有n个人和m组朋友关系。n个人的编号为1到n。第二行到第m+1行每行包括两个数字a和b,代表这两个人互相认识。当n和m都等于0时,输入结束。

输出
每组数据输出n行,对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。

测试说明
平台会对你编写的代码进行测试:

测试输入:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 8
1 2
2 3
3 4
4 5
5 6
6 7
7 8
9 10
0 0

预期输出:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%
1: 70.00%
2: 80.00%
3: 80.00%
4: 80.00%
5: 80.00%
6: 80.00%
7: 80.00%
8: 70.00%
9: 20.00%
10: 20.00%

#include <iostream>
#include <iomanip>
#define MAXSIZE 100
#define INFINITE 32767
using namespace std;
void CreateUDG(int G[][MAXSIZE], int m, int n) 
{//创建无向图的邻接矩阵,n个人,m组朋友关系 
	for (int i=0;i<n;i++)      //初始化为无穷大 
		for (int j=0;j<n;j++)
			G[i][j]=INFINITE;				
	int a, b;
	for (int i=0;i<m;i++) {			//有边则改为1 
		cin>>a>>b;						
		G[a-1][b-1]=1;
		G[b-1][a-1]=1;
	}
}
int FindMinPath(bool S[], int D[], int n) 
{//根据当前的D,选择最小的那个D[i],即为到起点的最短距离,对应的顶点下标为i
	int min=INFINITE;
	int index=-1;
	for (int i=0;i<n;i++) {
		if (!S[i]&&D[i]<min) {
			min=D[i];
			index=i;
		}
	}
	return index;
}

float SixDegree_DIJ(int G[][MAXSIZE], int n, int start) 
{//求从start到其他各顶点路径小于7的个数
/**************begin************/
  bool S[MAXSIZE]={false};
    int D[MAXSIZE];
    for (int i=0;i<n;i++) {
        D[i]=G[start][i];      
    }
    S[start]=true;
    for (int i=1;i<n;i++) {
        int v=FindMinPath(S,D,n);
        if (v == -1) break;
        S[v]=true;
        for (int w=0;w<n;w++) {
            if (!S[w] && G[v][w] != INFINITE && D[v]+G[v][w]<D[w]) {
                D[w]=D[v]+G[v][w];
            }
        }
    }

    int count = 0; // 计数小于等于6的结点数
    for (int i = 0; i < n; i++) {
        if (i != start && D[i] <= 6) {
            count++;
        }
    }

    return float(count+1) / n ;


/**************end************/
}

int main() 
{
	int n,m;
	while (true) {
		cin>>n>>m;
		if (n==0&&m==0) break;
		int G[MAXSIZE][MAXSIZE]={ 0 };
		CreateUDG(G,m,n);
		for (int i=0;i<n;i++) {	//每个顶点作为start,输出路径长度小于等于6的个数的比例 
			cout<<i+1<<": "<<fixed<<setprecision(2)<<SixDegree_DIJ(G,n,i)*100<<"%"<<endl;
		}
	}
	return 0;
} 

第11关:基于邻接表的深度优先遍历

任务描述
一个连通图采用邻接表作为存储结构。设计一个算法,实现从顶点v出发的深度优先遍历的非递归过程。

编程要求
输入
多组数据,每组m+2数据行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个整数h和k,代表边依附的两个顶点。第m+2行有一个整数d,代表从d开始遍历。当n和m都等于0时,输入结束。

输出
每组数据输出一行,为深度优先搜索的遍历结果。每两个数字之间用空格隔开。

测试说明
平台会对你编写的代码进行测试:

测试输入:
3 2
1 2
1 3
1
2 1
1 2
2
0 0

预期输出:
1 2 3
2 1

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSIZE 100
using namespace std;
typedef struct ArcNode
{//边结点
	int data;
	struct ArcNode *nextarc; //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
	int data;
	ArcNode *firstarc;  //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MAXSIZE];    //AdjList表示邻接表类型
typedef struct
{//邻接表
	AdjList vertices;
	int vexnum,arcnum;    //图的当前顶点数和边数
}ALGraph;
typedef struct
{//顺序栈
	int *base;          //栈底指针
	int *top;           //栈顶指针
	int stacksize;      //栈可用的最大容量
}SqStack;
void InitStack(SqStack &S)
{//顺序栈的初始化
	S.base=new int[MAXSIZE];   //动态分配一个最大容量MAXSIZE的数组空间
	S.top=S.base;           //top初始为base,空栈
	S.stacksize=MAXSIZE;
}
void Push(SqStack &S,int e)
{//入栈操作
	if(S.top-S.base==S.stacksize)   //栈满
		return;
	*S.top=e;    //元素e压入栈顶
	S.top++;        //栈顶指针加1
}
void Pop(SqStack &S,int &e)
{//出栈操作
	if(S.base==S.top)    //栈空
		return;
	S.top--;        //栈顶指针减1
	e=*S.top;        //将栈顶元素赋给e
}
bool StackEmpty(SqStack S)
{//判空操作
	if(S.base==S.top)    //栈空返回true
		return true;
	return false;
}
bool visited[MAXSIZE];    //访问标志数组,初始为false
int CreateUDG(ALGraph &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
    G.vexnum=vexnum;     //输入总顶点数
	G.arcnum=arcnum;     //输入总边数
	if(G.vexnum>MAXSIZE) return ERROR;  //超出最大顶点数则结束函数
	int i,h,k;
	for(i=1;i<=G.vexnum;i++)   //构造表头结点表
    {
        G.vertices[i].data=i;
        visited[i]=false;
        G.vertices[i].firstarc=NULL;
    }
    ArcNode *p1,*p2;
    for(i=0;i<G.arcnum;i++)   //输入各边,头插法构造邻接表
    {
        cin>>h>>k;
        p1=new ArcNode;
        p1->data=k;
        p1->nextarc=G.vertices[h].firstarc;
        G.vertices[h].firstarc=p1;
        p2=new ArcNode;
        p2->data=h;
        p2->nextarc=G.vertices[k].firstarc;
        G.vertices[k].firstarc=p2;
    }
    return OK;
}
void DFS(ALGraph G,int v,SqStack S)
{//从第v个顶点出发非递归实现深度优先遍历图G
/**************begin************/
   InitStack(S);
    Push(S, v); 
    visited[v] = true; 
    bool firstVertex = true; 

    while (!StackEmpty(S)) {
        Pop(S, v); 

        if (!firstVertex) {
            cout << " "; 
        } else {
            firstVertex = false;
        }

        cout << v;

        ArcNode* p = G.vertices[v].firstarc;
        while (p) {
            if (!visited[p->data]) {
                Push(S, p->data); 
                visited[p->data] = true; 
            }
            p = p->nextarc;
        }
    }
    cout << endl;
    /**************end************/
}
int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		if(n==0&&m==0) break;
		ALGraph G;
		SqStack S;
		CreateUDG(G,n,m);   //创建无向图G
		int d;             //从d开始遍历
		cin>>d;
		DFS(G,d,S);    //基于邻接表的深度优先遍历
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值