数据结构——浙大版中国大学mooc(week7)

课程给出代码

C语言:邻接表存储 - 无权图的单源最短路算法

/* 邻接表存储 - 无权图的单源最短路算法 */
 
/* dist[]和path[]全部初始化为-1 */
void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S )
{
    Queue Q;
    Vertex V;
    PtrToAdjVNode W;
     
    Q = CreateQueue( Graph->Nv ); /* 创建空队列, MaxSize为外部定义的常数 */
    dist[S] = 0; /* 初始化源点 */
    AddQ (Q, S);
 
    while( !IsEmpty(Q) ){
        V = DeleteQ(Q);
        for ( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */
            if ( dist[W->AdjV]==-1 ) { /* 若W->AdjV未被访问过 */
                dist[W->AdjV] = dist[V]+1; /* W->AdjV到S的距离更新 */
                path[W->AdjV] = V; /* 将V记录在S到W->AdjV的路径上 */
                AddQ(Q, W->AdjV);
            }
    } /* while结束*/
}

C语言:邻接矩阵存储 - 有权图的单源最短路算法

/* 邻接矩阵存储 - 有权图的单源最短路算法 */
 
Vertex FindMinDist( MGraph Graph, int dist[], int collected[] )
{ /* 返回未被收录顶点中dist最小者 */
    Vertex MinV, V;
    int MinDist = INFINITY;
 
    for (V=0; V<Graph->Nv; V++) {
        if ( collected[V]==false && dist[V]<MinDist) {
            /* 若V未被收录,且dist[V]更小 */
            MinDist = dist[V]; /* 更新最小距离 */
            MinV = V; /* 更新对应顶点 */
        }
    }
    if (MinDist < INFINITY) /* 若找到最小dist */
        return MinV; /* 返回对应的顶点下标 */
    else return ERROR;  /* 若这样的顶点不存在,返回错误标记 */
}
 
bool Dijkstra( MGraph Graph, int dist[], int path[], Vertex S )
{
    int collected[MaxVertexNum];
    Vertex V, W;
 
    /* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */
    for ( V=0; V<Graph->Nv; V++ ) {
        dist[V] = Graph->G[S][V];
        if ( dist[V]<INFINITY )
            path[V] = S;
        else
            path[V] = -1;
        collected[V] = false;
    }
    /* 先将起点收入集合 */
    dist[S] = 0;
    collected[S] = true;
 
    while (1) {
        /* V = 未被收录顶点中dist最小者 */
        V = FindMinDist( Graph, dist, collected );
        if ( V==ERROR ) /* 若这样的V不存在 */
            break;      /* 算法结束 */
        collected[V] = true;  /* 收录V */
        for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W */
            /* 若W是V的邻接点并且未被收录 */
            if ( collected[W]==false && Graph->G[V][W]<INFINITY ) {
                if ( Graph->G[V][W]<0 ) /* 若有负边 */
                    return false; /* 不能正确解决,返回错误标记 */
                /* 若收录V使得dist[W]变小 */
                if ( dist[V]+Graph->G[V][W] < dist[W] ) {
                    dist[W] = dist[V]+Graph->G[V][W]; /* 更新dist[W] */
                    path[W] = V; /* 更新S到W的路径 */
                }
            }
    } /* while结束*/
    return true; /* 算法执行完毕,返回正确标记 */
}

C语言:邻接矩阵存储 - 多源最短路算法

/* 邻接矩阵存储 - 多源最短路算法 */
 
bool Floyd( MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] )
{
    Vertex i, j, k;
 
    /* 初始化 */
    for ( i=0; i<Graph->Nv; i++ )
        for( j=0; j<Graph->Nv; j++ ) {
            D[i][j] = Graph->G[i][j];
            path[i][j] = -1;
        }
 
    for( k=0; k<Graph->Nv; k++ )
        for( i=0; i<Graph->Nv; i++ )
            for( j=0; j<Graph->Nv; j++ )
                if( D[i][k] + D[k][j] < D[i][j] ) {
                    D[i][j] = D[i][k] + D[k][j];
                    if ( i==j && D[i][j]<0 ) /* 若发现负值圈 */
                        return false; /* 不能正确解决,返回错误标记 */
                    path[i][j] = k;
                }
    return true; /* 算法执行完毕,返回正确标记 */
}

07-图4 哈利·波特的考试 (25 分)

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。
现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。
输入格式:
输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。
输出格式:
输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。

#include<stdio.h>
#include<stdbool.h>

#define MaxVertexNum 100 /*设置最大顶点数为100*/
#define INF 99999        /*定义无穷数值为99999*/
typedef int Vertex;      /*顶点下标表示顶点*/
typedef int WeightType;  /*边的权值*/
/*typedef char DataType;   /*顶点存储的数据类型*/
/*定义边*/
typedef struct ENode *PtrToENode;
struct ENode{
	Vertex V1,V2;        /*有向边<V1,V2>*/
	WeightType Weight;   /*权值*/
};
typedef PtrToENode Edge;
/*定义图顶点*/
typedef struct GNode *PtrToGNode;
struct GNode{
	int Nv;              /*顶点数*/
	int Ne;              /*边数*/
	WeightType G[MaxVertexNum][MaxVertexNum];
	/*DataType Data[MaxVertexNum];/*顶点数据*/
};
typedef PtrToGNode MGraph;/*以邻接矩阵存储的图类型*/

MGraph CreatGraph(int VertexNum){
	Vertex V, M;
	MGraph Graph;
	Graph=(MGraph)malloc(sizeof(struct GNode));
	Graph->Nv=VertexNum;
	Graph->Ne=0;
	for(V=0;V<Graph->Nv;V++)
		for(M=0;M<Graph->Nv;M++)
				Graph->G[V][M]=INF;
	return Graph;
}

void InsertEdge(MGraph Graph,Edge E){
	Graph->G[E->V1][E->V2]=E->Weight;
	Graph->G[E->V2][E->V1]=E->Weight;	/*无向图*/
}

MGraph BuildGraph(){
	MGraph Graph;
	Edge E;
	/*Vertex  V*/
	int Nv, i;
	scanf("%d",&Nv);        /*读入顶点个数*/
	Graph=CreatGraph(Nv);   /*创建only顶点无边的图*/
	scanf("%d",&(Graph->Ne));
	if(Graph->Ne!=0){
		E=(Edge)malloc(sizeof(struct ENode));/*建立边节点*/
		for(i=0;i<Graph->Ne;i++){
			scanf("%d %d %d",&E->V1,&E->V2,&E->Weight);
			E->V1--;E->V2--;/*起始节点的序号从0开始*/
			InsertEdge(Graph,E);
		}
	}
	/*for(每个顶点Nv)读入数值*/
	return Graph; 
}

WeightType FindMaxDist(WeightType D[][MaxVertexNum],Vertex i, int N){
	WeightType MaxDist;
	Vertex j;
	MaxDist=0;
	for(j=0;j<N;j++)
		if(i!=j&&D[i][j]>MaxDist)
			MaxDist=D[i][j];
	return MaxDist;
}

void Floyd( MGraph Graph, WeightType D[][MaxVertexNum]/*, Vertex path[][MaxVertexNum] */)
{
    Vertex i, j, k;
    /* 初始化 */
    for ( i=0; i<Graph->Nv; i++ )
        for( j=0; j<Graph->Nv; j++ ) {
            D[i][j] = Graph->G[i][j];
            /*path[i][j] = -1;*/
        }
    for( k=0; k<Graph->Nv; k++ )
        for( i=0; i<Graph->Nv; i++ )
            for( j=0; j<Graph->Nv; j++ )
                if( D[i][k] + D[k][j] < D[i][j] ) {
                    D[i][j] = D[i][k] + D[k][j];
                    /*if ( i==j && D[i][j]<0 ) /* 若发现负值圈 
                        return false; /* 不能正确解决,返回错误标记 
                     path[i][j] = k;*/
                }
    /*return true; /* 算法执行完毕,返回正确标记 */
}

void FindAnimal(MGraph Graph){
	WeightType D[MaxVertexNum][MaxVertexNum],MaxDist,MinDist;
	Vertex Animal, i;
	Floyd(Graph,D);
	MinDist=INF;
	for(i=0;i<Graph->Nv;i++){
		MaxDist=FindMaxDist(D,i,Graph->Nv);
		if(MaxDist==INF){
			printf("0\n");
			return;
		}
		if(MinDist>MaxDist){/*找到最长距离更小的动物,跟新值,记录编号*/
			MinDist=MaxDist;
			Animal=i+1;
		}
	}
	printf("%d %d\n",Animal,MinDist);
}

int main(){
	MGraph G=BuildGraph();
	FindAnimal(G);
	return 0;
}

07-图5 Saving James Bond - Hard Version (30 分)

This time let us consider the situation in the movie “Live and Let Die” in which James Bond, the world’s most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape – he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head… Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).
Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him a shortest path to reach one of the banks. The length of a path is the number of jumps that James has to make.
Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.
Output Specification:
For each test case, if James can escape, output in one line the minimum number of jumps he must make. Then starting from the next line, output the position (x,y) of each crocodile on the path, each pair in one line, from the island to the bank. If it is impossible for James to escape that way, simply give him 0 as the number of jumps. If there are many shortest paths, just output the one with the minimum first jump, which is guaranteed to be unique.
没时间做了,代码来源:https://www.cnblogs.com/minesweeper/p/5954733.html

#include "iostream"
#include "math.h"
#include "queue"
#include "stack"
#include "algorithm"
using namespace std;
int n, m;
#define MINLEN 42.5
struct Pointer {
    int x;
    int y;
}point[101];
bool answer = false; /* 记录007能否安全逃生~~ */
bool visited[101] = { false }; /* 判断当前点是否被访问过 */
int path[101] = {-1}; /* 记录跳跃过程中踩过的鳄鱼 */
bool isSave(int x) { /* 判断从当前点能否跳到岸上 */
    if ((point[x].x - m <= -50) || (point[x].x + m >= 50) || (point[x].y - m <= -50) || (point[x].y + m >= 50))
        return true;
    return false;
}

bool jump(int x, int y) { /* 判断2个点距离是否在跳跃能力内 */
    int p1 = pow(point[x].x - point[y].x, 2);
    int p2 = pow(point[x].y - point[y].y, 2);
    int r = m * m;
    if (p1 + p2 <= r)
        return true;
    return false;
}

int firstJump(int x) {  /* 当007处于孤岛时 第一次可以选择跳的鳄鱼 因为第一次判断能否跳跃的计算方法与后面dfs不相同 所以要单独写 */
    int p1 = pow(point[x].x, 2);
    int p2 = pow(point[x].y, 2);
    int r = (m + 7.5) * (m + 7.5);
    if (p1 + p2 <= r) {
        return p1+p2;
    }
    return 0;
}
bool cmp(int a,int b) {
    return firstJump(a) < firstJump(b);
}
void bfs() { /* 用bfs来判断最少要踩几个小鳄鱼才能上岸 */
    int b[101];
    queue<int>q; 
    /* 将第一步能踩到的鳄鱼按距离从小到大的顺序进队列~ 因为输出结果要保证在踩的鳄鱼数量相等的情况下 输出第一步距离最短的~~*/
    for (int i = 0; i < n; i++) {
        b[i] = i;
    }
    sort(b, b + n, cmp); /* 按照第一步的距离排序~~~ */
    int last;
    for (int i = 0; i < n; i++) {
        if (firstJump(b[i])) { /* 能跳上去! */
            q.push(b[i]);
            visited[b[i]] = true; /* 指向当前层数最后一个数~ */
            last = b[i];
        }
    }
    int step = 2;  /* 记录最少要跳跃的次数 */
    int tail; 
    while (!q.empty()) {
        int p = q.front();
        q.pop();
        if (isSave(p)) {
            int k = 1;
            stack<int> s;
            cout << step << endl;
            while (k < step) {
                //cout << point[p].x << " " << point[p].y << endl;
                s.push(p);
                p = path[p];
                k++;
            }
            while (!s.empty()) {
                p = s.top();
                s.pop();
                cout << point[p].x << " " << point[p].y << endl;
            }
            return;
        }
        for (int i = 0; i < n; i++) {
            if (!visited[i] && jump(p, i)) { /* 没踩过并且能跳到 */
                q.push(i);
                path[i] = p; /* 记得当前进队节点的父节点~ */
                visited[i] = true;
                tail = i; /* 指向下一层的最后一个元素 */
            }
        }
        if (last == p) { /* 即将进入下一层~ */
            step += 1;
            last = tail;
        }
    }
    if (q.empty()) { /* 如果队列为空  说明没跳出去啊~ */
        cout << "0" << endl;
    }
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> point[i].x >> point[i].y;
    }
    if (m >= MINLEN) { /* 可以直接从孤岛上提到岸上 直接输出 */
        cout << "1" << endl;
        return 0;
    }
    bfs();
    return 0;
}

07-图6 旅游规划 (25 分)

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
没时间做了,代码来源:https://blog.csdn.net/qq_37618760/article/details/83386015

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define INF 10000000
using namespace std;
const int Max=500;
int Map[Max+5][Max+5];
int Cost[Max+5][Max+5];
int dis[Max+5],MCost[Max+5];
bool vis[Max+5]={false};
int Min;
void Dijkstra(int v0,int v,int d){
 
     dis[v0]=0; vis[v0]=true;
    for(int i=0;i<v;i++){
        Min=INF;
        for(int k=0;k<v;k++){
            if(!vis[k]){
                if(dis[k]<Min){
                    Min=dis[k];
                    v0=k;
                }
            }
        }
        vis[v0]=true;
        for(int k=0;k<v;k++){
            if(!vis[k]&&Min+Map[v0][k]<dis[k]){
                dis[k]=Min+Map[v0][k];
                MCost[k]=MCost[v0]+Cost[v0][k];
            }
            else if(!vis[k]&&Min+Map[v0][k]==dis[k]&&MCost[k]>MCost[v0]+Cost[v0][k]){
                MCost[k]=MCost[v0]+Cost[v0][k];            }
        }
    }
}
int main(){
    int v,e,s,d;
    scanf("%d %d %d %d",&v,&e,&s,&d);
    for(int i=0;i<v;i++)
    for(int j=0;j<v;j++){
        Map[i][j]=Map[j][i]=INF;
        Cost[i][j]=Cost[j][i]=INF;
        //设置为双向连通,并初始化为最大值
    }
    for(int i=0;i<e;i++){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        Map[a][b]=Map[b][a]=c;
        Cost[a][b]=Cost[b][a]=d;
 
    }
    for(int i=0;i<v;i++){
        dis[i]=Map[i][s];//Map[i][s]为点i到起始点的距离
        MCost[i]=Cost[i][s];
    }
    Dijkstra(s,v,d);
    cout<<dis[d]<<" "<<MCost[d]<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值