浙大2020年Mooc数据结构笔记--第七讲 图(中)

浙大2020年Mooc数据结构笔记–第七讲 图(中)

〇、前言

  • 这几天开始跟着学数据结构,鉴于当初数据结构实在学的太弱,加之这项工作算是为大家之后复习、机试铺路。确实是一个迫切需要做的大规模工作。行胜于言,虽然从第二篇开始,坚持下去。

在这里插入图片描述

  • 此文部分为自己写,部分参考网上内容。提前说一下哈。期待批评指正。

一、Dijkstra算法

Dijkstra主要解决单源最短路径问题
在这里插入图片描述

二、Floyd算法

解决多源最短路径问题
在这里插入图片描述

三、哈利波特的考试

在这里插入图片描述

三、课后题

在这里插入图片描述

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

在这里插入图片描述
输入样例:

6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80

输出样例:

4 70

#include<iostream>
#include<string.h>
using namespace std;
#define MAX 100
#define INF 65535

int N = 0; //节点个数
int M = 0; //边的个数
int G[MAX][MAX] = { 0 };
int D[MAX][MAX] = { 0 };

void initD() {
	for (int i = 0; i < MAX; i++) {
		for (int j = 0; j < MAX; j++) {
			D[i][j] = INF;
		}
	}
}

void initG() {
	for (int i = 0; i < MAX; i++) {
		for (int j = 0; j < MAX; j++) {
			G[i][j] = INF;
		}
	}
}

void Floyd() {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
				D[i][j] = G[i][j];
		}
	}
	for (int i = 0; i < N; i++) {
		D[i][i] = 0;
	}
	printf("1\n");
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			printf("%d  ", D[i][j]);
		}
		printf("\n");
	}

	for (int k = 0; k < N; k++) {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (D[i][k] !=INF&& D[k][j] !=INF&&D[i][k] + D[k][j] < D[i][j]) {
					D[i][j] = D[i][k] + D[k][j];
				}
			}
		}
	}
}

//找每行最大值的最小值
void  FindAnimal() {
	int dis = INF;//记录最后的距离
	int k = 0;//记录最后拿的动物
	for (int i = 0; i < N; i++) {
		int max = 0;
		for (int j = 0; j < N; j++) {
			if (max < D[i][j]) {
				max = D[i][j];
			}
		}
		if (max < dis) {
			dis = max;
			k = i+1;
		}
	}
	printf("%d %d", k, dis);

}
int main() {
	int eage1, eage2;
	int weight;
	initG();
	scanf("%d %d", &N, &M);				//N 为结点数,M为边数
	for (int i = 0; i < M; i++) {
		scanf("%d %d %d", &eage1, &eage2,&weight);
		G[eage1 - 1][eage2 - 1] = weight;
		G[eage2 - 1][eage1 - 1] = weight;
	}
	initD();  // 初始化D[][]数组
	Floyd();

	printf("2\n");
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			printf("%d  ", D[i][j]);
		}
		printf("\n");
	}

	FindAnimal();
	return 0;
}

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

在这里插入图片描述
Sample Input 1:

17 15
10 -21
10 21
-40 10
30 -50
20 40
35 10
0 -10
-25 22
40 -40
-30 30
-10 22
0 11
25 21
25 10
10 10
10 35
-30 10

Sample Output 1:

4
0 11
10 21
10 35

Sample Input 2:

4 13
-12 12
12 12
-12 -12
12 -12

Sample Output 2:

0
将起点集合和终点集合找到,使用Floyd 多源最短路径找出最短距离即可,并用path二维矩阵记录路径。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXV = 110;
const int INF = 65535;
using namespace std;
struct point{            
    int x,y;
}p[MAXV];
const double RADIUS = 7.5; //半径 
int N,D;
int G[MAXV][MAXV],path[MAXV][MAXV];
vector<int> first,last;
double getDis(int i, int j){ //计算两点间距离
	return sqrt(pow(p[i].x - p[j].x, 2) + pow(p[i].y - p[j].y,2)); 
}
bool cmp(int i,int j){       //排序函数中的比较函数。把第一次能跳上的鳄鱼按照近小岛的距离升序排列 
    return getDis(i,0) < getDis(j,0);
}
bool isFirst(int i){ //第一跳能到达 
	return getDis(i,0) <= D + RADIUS;
}
bool isLast(int i){ //最后一跳能到达 
	return (abs(p[i].x) + D >= 50||abs(p[i].y) + D >= 50);
}
void getWay(int st, int ed){  //打印出经过的鳄鱼的坐标 
    printf("%d %d\n",p[st].x, p[st].y);
    while(st != ed){
        st = path[st][ed];
        printf("%d %d\n",p[st].x,p[st].y);
    }
}
void Floyd(){
	for(int k = 1; k <= N; k++){       
        for(int i=1; i <= N; i++){
            for(int j = 1; j <= N; j++){
                if(G[i][k] + G[k][j] < G[i][j]){
                    G[i][j] = G[i][k] + G[k][j];
                    path[i][j] = path[i][k];
                }
            }
        }
	}
}
int main()
{
	fill(G[0], G[0] + MAXV*MAXV, INF); //初始化图 
	for(int i = 1; i < MAXV; i++)
		for(int j = 1; j < MAXV; j++)
			path[i][j] = j; //初始化路径 
    cin>>N>>D; 
    if(D >= 50-RADIUS){             //一步到岸边 
        printf("1\n");
        return 0;
    }
    p[0].x = p[0].y = 0;        
    for(int i = 1; i <= N; i++){   //数组下标1开始存储数据 
        cin>>p[i].x>>p[i].y;
        if((getDis(i,0) <= RADIUS)||abs(p[i].x) >= 50||abs(p[i].y) >= 50) {   //当鳄鱼在岸上或在小岛上时,这条鳄鱼可以忽略不计。因此鳄鱼数量N减一,下条鳄鱼顶替它的数组中的位置 
            i--;
            N--;
        }   
    }
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){
            if(getDis(i,j) <= D){
                if(i == j)   
                    G[i][j] = G[j][i] = 0;
                else
                    G[i][j] = G[j][i] = 1;                   
			}
        }   
    }
    for(int i=1;i<=N;i++)//加入起点集 
        if(isFirst(i))	
			first.push_back(i);  
    for(int i=1;i<=N;i++){ //加入终点集 
		if(isLast(i)) 
			last.push_back(i);
	}
	Floyd();
	sort(first.begin(), first.end(), cmp); //起点集按与小岛的距离从小到达排序 
    int minStep = INF, st, ed;    //分别为最小的跳跃数,起点下标,终点下标 
	for(int i=0; i < first.size(); i++){
    	int u = first[i];
        for(int j = 0; j < last.size(); j++){
        	int v = last[j];
            if(G[u][v] < minStep){
            	minStep = G[u][v];
            	st = u;
            	ed = v;
			}
        }
    }
    if(minStep != INF){ 
        printf("%d\n",minStep + 2); //minStep为起点到终点的距离,加上从小岛跳到起点鳄鱼,从终点鳄鱼跳到岸边的2步 
        getWay(st,ed);//打印路径 
    }else  //当最小的跳跃数为INF,则不可能逃脱 
        printf("0");
    return 0;
}

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

在这里插入图片描述
输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40

#include <stdio.h>
#define INFINITY 100000000
#define ERROR -1

typedef int Vertex;
struct Gnode {
    int weight;
    int expenses;
};
struct Gnode G[500][500];
int Nv, Ne;//边数控制输入行数,顶点数控制for循环范围
int strpos, despos;//起点,终点
int visited[500] = { 0 };
int dist[500], cost[500];//最短路径以及最小花费

void buildgraph() {
    int v1, v2, w, ex;
    int i, j;
    //初始化图
    for (i = 0; i < Nv; i++) {
        for (j = 0; j < Nv; j++) {
            G[i][j].weight = INFINITY;
            G[i][j].expenses = INFINITY;
        }
        G[i][i].weight = 0;
        G[i][i].expenses = 0;
        dist[i] = INFINITY;
        cost[i] = INFINITY;
    }
    for (i = 0; i < Ne; i++) {
        scanf("%d %d %d %d", &v1, &v2, &w, &ex);
        G[v1][v2].weight = w;
        G[v1][v2].expenses = ex;
        G[v2][v1].weight = w;
        G[v2][v1].expenses = ex;
    }
}

/* 邻接矩阵存储 - 有权图的单源最短路算法 */

Vertex FindMinDist() {
    /* 返回未被收录顶点中dist最小者 */
    int MinV, V;
    int MinDist = INFINITY;

    for (V = 0; V < Nv; V++) {
        if (!visited[V] && dist[V] < MinDist) {
            /* 若V未被收录,且dist[V]更小 */
            MinDist = dist[V]; /* 更新最小距离 */
            MinV = V; /* 更新对应顶点 */
        }
    }
    if (MinDist < INFINITY) /* 若找到最小dist */
        return MinV; /* 返回对应的顶点下标 */
    else
        return ERROR;  /* 若这样的顶点不存在,返回错误标记 */
}

int Dijkstra() {
    Vertex V, W;

    /* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */
    for (V = 0; V < Nv; V++) {
        dist[V] = G[strpos][V].weight;
        cost[V] = G[strpos][V].expenses;
    }
    /* 先将起点收入集合 */
    dist[strpos] = cost[strpos] = 0;
    visited[strpos] = 1;//对起点进行初始化
        
    while (1) {
        /* V = 未被收录顶点中dist最小者 */
        V = FindMinDist();
        if (V == ERROR) /* 若这样的V不存在 */
            break;      /* 算法结束 */
        visited[V] = 1;  /* 收录V */
        for (W = 0; W < Nv; W++) /* 对图中的每个顶点W */
            /* 若W是V的邻接点并且未被收录 */
            if (!visited[W] && G[V][W].weight < INFINITY) {
                if (dist[V] + G[V][W].weight < dist[W]) {
                    dist[W] = dist[V] + G[V][W].weight;
                    cost[W] = cost[V] + G[V][W].expenses;
                }
                else if ((dist[V] + G[V][W].weight == dist[W]) && (cost[V] + G[V][W].expenses < cost[W]))
                    cost[W] = cost[V] + G[V][W].expenses;
            }
    } /* while结束*/
    return 1; /* 算法执行完毕,返回正确标记 */
}

int main() {
    scanf("%d %d %d %d", &Nv, &Ne, &strpos, &despos);
    buildgraph();
    Dijkstra();
    printf("%d %d", dist[despos], cost[despos]);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值