图之拯救007

这一章学习了图。

一、图的基本概念与原理

  1. 有向图与无向图;

    顶点

    弧:弧尾和弧头

    度:出度和入度

    顶点

    邻接点

    连通图

    完全图:边数=n(n-1)/2

    生成树:边数=n-1

  2. 图的表示法

  3. 图的遍历

  4. 最小生成树:注意最小生成树的应用

二、图的存储方式

对于无向图:存储顶点及边

对于有向图:存储顶点及弧

弧尾———-权值———弧尾

邻接矩阵

顶点的表示方法:

顶点索引 顶点数据

弧的表示方法:

邻接矩阵

顶点的表示方法:

顶点索引 出弧链表头指针 顶点数据

弧的表示方法:

弧头顶点索引 下一条弧指针 弧数据

最难理解的是出弧链表头指针及下一条弧指针

一个顶点发出多条弧时,第一条弧里带有下一条弧的指针;

弧数据相当于权重

十字链表

也用于存储有向图;

顶点的表示方法
顶点索引 顶点数据 以该顶点为弧尾的弧节点指针 以该顶点为弧头的弧节点指针
弧的表示方法
弧尾顶点索引 弧头顶点索引 弧尾相同的下一条弧的指针 弧头相同的下一条弧的指针 弧的数据

邻接多重表

用于存储无向图;

顶点的表示方法
顶点索引 连接该顶点的边 顶点数据
边的表示方法

三、图的遍历

图的搜索按搜索方向分为:深度优先搜索和广度优先搜索;

深度优先搜索遵循二叉树搜索的“根左右”的原则,广度优先搜索是一层一层的节点进行搜索;

1、最小生成树

有普利姆算法,克鲁斯卡尔算法两种算法;普里姆是归并点;而克鲁斯卡尔是归并边;

普利姆(prim)算法

算法思想:

[ ] 任意选择一个顶点,将其放入点集合中;下图选的顶点为A;
[ ] 将与A顶点相连的边放入待选边集合中,如下图的A-B(6) A-F(1) A-E(5)所示;
[ ] 选择一个权值最小的边放入边集合中,下图中是A-F(1);将该边所连的顶点F放入点集合中;
[ ] 将与F点相连的边放入待选边集合中,如F-B(2) F-E(9) F-C(8) F-D(4),重复上面2~3步的过程,直到所有的点都被包含在点集合中(图中的点集合少写了个E)
[ ] 普利姆算法适用于稠密的图,即边数较多的图,时间复杂度o(n^2);


克鲁斯卡尔(Kruskal)算法

算法思想:

[ ] 将所有边放入待选边集合中;
[ ] 取出当前待选边集合中权值最小的边放入已选边集合中,将边所连接的两个顶点放入已涉及点集合中
[ ] 重复步骤2,如果已涉及的点的集合中的点不处于同一棵树中,则继续重复步骤2,直到已涉及的点的集合包含所有的点且所有点都在同一棵树中,最小生成树也就随之产生了;
[ ] 克鲁斯卡尔算法适用于边数较少的稀疏图,算法复杂度为o(n^2);

拯救007

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <string>
#include <cstring>
#include <cmath>
 
using namespace std;
const int maxn=150;
struct Node
{
    double x,y;
} node[maxn];
double d_len(int x,int y)
{
    double xx=node[x].x-node[y].x;//两点之间x坐标间距离
    double yy=node[x].y-node[y].y;//两点之间y坐标间距离
    return sqrt(xx*xx+yy*yy);//对距离求平方,比较平方可减少不必要麻烦
}
int n;
double d;
double G[maxn][maxn];
int f;
int vis[maxn];
void dfs(int x)
{
    if(vis[x]) return ;
    vis[x]=1;
    double xx=fabs(node[x].x-50);
    double yy=fabs(node[x].y-50);
    if(xx<=d||yy<=d)//判断007是否可以直接跳到对岸
    {
        f=1;
        return ;
    }
    for(int i=0; i<n; i++)//确定007逃生路径
    {
        if(vis[i]) continue;
        if(G[x][i]<=d)
        {
            dfs(i);
        }
    }
}
int main()
{
    cin>>n>>d;
    f=0;
    for(int i=0; i<n; i++)
    {
        cin>>node[i].x>>node[i].y;//输入鳄鱼的坐标
    }
    for(int i=0; i<n; i++)
    {
        for(int j=i; j<n; j++)
        {
            G[i][j]=G[j][i]=d_len(i,j);
        }
    }
    if(d>=(50-15))//直接跳过去对岸
    {
        cout<<"Yes"<<endl;
        return 0;
    }
    for(int i=0; i<n; i++)
    {
        double x=fabs(node[i].x-15);//返回绝对值
        double y=fabs(node[i].y-15);//返回绝对值
        if(x<=d||y<=d)//满足条件,进行下一步跳跃
        {
            memset(vis,0,sizeof(vis));//memset函数,将vis中的内容用0替换并返回
            dfs(i);
        }
    }
    if(f) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
 
    return 0;
}

思路:直接暴力就行,最多只有一百个鱼,一开始没有思路,后来想想用一个简单的dfs即可。

上次目标是复习第四章第五章,有进行复习,但还要继续,这次目标就定为多打打树和图的代码,熟悉两者的运用。加油!

猜你喜欢

转载自www.cnblogs.com/lizixiang123/p/10891164.html
007