编程题实训-图

第1关:迷宫问题

任务描述

密密被困在一个迷宫里,迷宫有n个路口,编号为1-n。密密现在站在第一个路口,出口编号为m。先给出每个路口通向何处,问密密能否逃出迷宫。

编程要求

输入

多组数据,每组数据n+2行。第一行为一个正整数n代表路口的个数,之后n行,这n行中的第i行为第i个路口的向左路口、向前路口、向右路口。最后一行为一个正整数m代表迷宫的终点。当n=0时输入结束。

输出

每组数据输出一行,若密密能走出迷宫,输出“YES”,否则输出“NO”。

#include <iostream>
using namespace std;
int m,n;//m:出口编号  n:入口
int tag;//输出标记
int DFS(int k,int (*a)[3])
{//深度搜索第k层,k:当前路口
/**************begin************/
    if(k==m) //到达出口
    {
        tag=1;
        return 0;
    }
    for(int i=0;i<3;i++)//遍历向左路口、向前路口、向右路口
    {
        if(0!=a[k][i]&&tag!=1)//如果当前路口有通路,并且没有走过
        {
            DFS(a[k][i],a);//进入下一个路口 ,递归
        }
    }
    return 0;
    /**************end************/
}
int main()
{
	while(cin>>n)
	{
	if(n==0)break;
	int i,j;
	tag=0;
	int a[n+1][3];//迷宫
	for(i=1;i<=n;i++)
		for(j=0;j<3;j++)
			cin>> a[i][j];
	cin>>m;
	DFS(1,a);//从第一层开始搜索
	if(tag==1)
		cout<<"YES"<<endl;
	else if(tag==0)
		cout<<"NO"<<endl;
	}
	return 0;
}

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

任务描述

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

编程要求

输入

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

输出

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

#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 i,n,v,Min,w;
    int S[MVNum];           //S[i]记录从源链0到终点
    n=G.vexnum;                         //N列表中的项目数
    int v0=LocateVex(G,V);     
    for(v=0;v<n;++v)      
    {
        S[v]=false;                   //首为空
        D[v]=G.arcs[v0][v];             //分为不同终端的短期数据库的初始初始化更改为右上角的值
        if(D[v]<MaxInt)
            Path[v]=v0;                  //V0之间进行选择,并将v的第一个要求设置为V0
        else
            Path[v]=-1;                //如果v0和v0之间没有差异,则v0的第一个要求设置为1
    }//for
    S[v0]=true;                     //将0添加到S
    D[v0]=0;                            
    for(i=1;i<n;++i)       
    {
        Min=MaxInt;
        for(w=0;w<n;++w)
            if(!S[w]&&D[w]<Min)    
            {
                v=w;
                Min=D[w];
            }
        S[v]=true;                          //添加S
        for(w=0;w<n;++w)  
            if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
            {
                D[w]=D[v]+G.arcs[v][w];     //更新D[w]
                Path[w]=v;                     //先前更改w的要求是v
            }//if
    }//for
    /**************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位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。

#include <iostream>
#include <iomanip>
#define MAXSIZE 100
#define INFINITE 36577
using namespace std;
void CreateUDG(int G[][MAXSIZE], int m, int n) 
{//使用连接短速度阵列的方法创建
	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) 
{//选择其中一个条件的当前最短期限,终点为n
	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) 
{//通过这个“新的开始”,我们可以计算法律系统中六个空时间点的数量,而开始是交换机指定时间点的第一级
/**************begin************/
    bool S[MAXSIZE];                        //S[]是按以下顺序开始的最短时间
    int D[MAXSIZE];                            //D[]是以下序列到达起点的最短时间
    for (int i=0;i<n;i++) {            //n结束基于初始激活区域
        S[i]=false;
        D[i]=INFINITE;
    }
    S[start]=true;                        //将起点添加到S
    D[start]=0;                            
    for (int i=0;i<n;i++) {          
        if (G[start][i]!=0)
            D[i]=G[start][i];
    }
/*--------初始区域完成或完成后,在相同的环境中启动事件,然后要求系统启动到一定的最小时间长度,然后将其添加到S板-------*/
    for (int i=0;i<n-1;i++) {
        int v=FindMinPath(S, D, n);
        if (v==-1) break;
        S[v]=true;                        
        for (int w=0;w<n;w++) {        
            if (!S[w]&&D[w]>D[v]+G[v][w]) {
                D[w]=D[v]+G[v][w];        //更新D[w]
            }
        }
    }
/*--------已请求点开始图[]中剩余短周期的数量,剩余短周期数量现在比其他两个短周期数量少,可以作为相关短周期的百分比列出-------*/
    float count=1;
    for (int i=0;i<n;i++) {
        if (D[i]<=6)
            count++;
    }
    return count/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++) {			//首次验证n年的中央时间管理后
			cout<<i+1<<": "<<fixed<<setprecision(2)<<SixDegree_DIJ(G,n,i)*100<<"%"<<endl;
		}
	}
	return 0;
}

第4关:基于邻接表的新顶点的增加

任务描述

给定一个无向图,在此无向图中增加一个新顶点。

编程要求

输入

多组数据,每组m+2行。第一行有两个数字n和m,代表有n个顶点和m条边。顶点编号为1到n。第二行到第m+1行每行有两个数字h和k,代表边依附的两个顶点。第m+2行有一个数字f,代表新插入的顶点编号。当n和m都等于0时,输入结束。

输出

每组数据输出n+1行。为增加顶点后的邻接表。每两个数字之间用空格隔开。

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100     //最大顶点数
using namespace std;
typedef struct ArcNode
{//边结点
	int adjvex;                //邻接点域:该边所指向的顶点的位置
	int data;                  //数据域:存储和边相关的信息
	struct ArcNode* nextarc;   //链域:指向下一条边的指针
}ArcNode;
typedef struct VNode
{//顶点信息
	int data;              //顶点结点的数据域
	ArcNode *firstarc;     //链域:指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];     //AdjList表示邻接表类型
typedef struct
{//邻接表
	AdjList vertices;
	int vexnum,arcnum;    //图的当前顶点数和边数
}ALGragh;
int CreateUDG(ALGragh &G,int vexnum,int arcnum)
{//采用邻接表表示法,创建无向图G
	G.vexnum=vexnum;     //输入总顶点数
	G.arcnum=arcnum;     //输入总边数
	if(G.vexnum>MVNum) return ERROR;  //超出最大顶点数则结束函数
  	for(int i=0;i<G.vexnum;++i)       //构造表头结点表
    {
        G.vertices[i].data=i+1;       //输入顶点值
        G.vertices[i].firstarc=NULL;   //初始化表头结点的指针域为NULL
    }
  	for(int j=0;j<G.arcnum;j++)      //输入各边,构造邻接表
    {
        int h,k;
		cin>>h>>k;                  //输入一条边依附的两个顶点h和k
		ArcNode* p1=new ArcNode;        //生成一个新的边结点*p1
		p1->adjvex=h-1;                 //邻接点序号为h-1
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值