前置知识
彻底搞懂克鲁斯卡尔(Kruskal)算法(附C++代码实现) - QuanHa - 博客园 (cnblogs.com)
白色点矩形是地牢,其中白线是按照krsukal算法连接的画总长最短的线连出来的路径
其中关键算法
#include <stdio.h>
#define MAX_VEX 12
#define MAX_EDGE 144
typedef struct edge {
int startpoint; // 起点在数组中的序号
int endpoint; // 终点在数组中的序号
int weight;
} edge;
typedef struct link {
int startx; // 起点的坐标
int starty;
int endx; // 终点的坐标
int endy;
int used; // 是否已经使用
int lenth; // 距离
edge edgelink;
} link;
typedef struct target {
int targeti = 0; // 左上角网格坐标
int targetj = 0;
int targetwidth = 0; // 长宽
int targetheight = 0;
int islive = 0;
// RenderTexture2D* picture; // 敌人贴图
// RenderTexture2D picture; // 敌人贴图
int** oldmap; // 局部复原数据
int** mapv3; // 像素也当成网格,每个记录像素是否能穿过
target* area; // 敌人内部的点
int arealenth; // 用于记录范围,lenth是半径
} target;
int find_root(int roots[], int n) {
while (roots[n] != -1) {
n = roots[n];
}
return n;
}
int main() {
link linkside[12][12]; // 兼容之前参数
int vex = 12; //顶点个数
int edgeside = 12 * 12; //边个数
link graph[MAX_EDGE];
edge graphv2[MAX_EDGE];
//
// for (int k = 0; k < edgeside; k++) {
// for (int n = 0; n <= 11; n++) {
// for (int m = 0; m <= 11; m++) {
// if (linkside[n][m].used == 0) {
// graph[k].startx = linkside[n][m].startx;
// graph[k].starty = linkside[n][m].starty;
// graph[k].endx = linkside[n][m].endx;
// graph[k].endy = linkside[n][m].endy;
// graph[k].lenth = linkside[n][m].lenth;
// graph[k].used = 1;
//
// graphv2[k].startpoint=n;
// graphv2[k].endpoint=m;
// graph[k].lenth=linkside[n][m].lenth;
// }
// }
// }
// }
for (int n = 0; n < 144; n++) {
graph[n].used = 0;
}
int k = 0;
for (int n = 0; n <= 11; n++) {
for (int m = 0; m <= 11; m++) {
if (linkside[n][m].used == 0) {
graph[k].startx = linkside[n][m].startx;
graph[k].starty = linkside[n][m].starty;
graph[k].endx = linkside[n][m].endx;
graph[k].endy = linkside[n][m].endy;
graph[k].lenth = linkside[n][m].lenth;
graph[k].used = 1;
graph[k].edgelink.startpoint = n;
graph[k].edgelink.endpoint = m;
graph[k].edgelink.weight = linkside[n][m].lenth;
k++;
}
}
}
// 标记不用数据
for (int n = 0; n < 144; n++) {
if (graph[n].used == 0) {
graph[n].lenth = 999999;
graph[n].edgelink.weight = 999999;
}
}
// 插入排序
link max;
int index;
for (int n = 0; n < 144; n++) {
index = n;
max = graph[n];
for (int m = n + 1; m < 144; m++) {
if (graph[m].lenth < max.lenth) {
max = graph[m];
index = m;
}
}
graph[index] = graph[n];
graph[n] = max;
}
int roots[MAX_VEX]; //根数组,存放各顶点的根节点,以区别是否属于同一个集合
edge MST[MAX_EDGE]; //存放最小生成树(minimum spanning tree)
int count = 0;
for (int n = 0; n < MAX_VEX; n++) {
roots[n] = -1;
}
// for (int n = 0; n < MAX_EDGE; n++) {
//
// }
for (int n = 0; n < MAX_EDGE; n++) {
if (graph[n].used == 1) {
int vex_m = find_root(roots, graph[n].edgelink.startpoint);
int vex_n = find_root(roots, graph[n].edgelink.endpoint);
if (vex_m != vex_n) { //如果两者的根节点不同,说明他们属于不同的集合,可以相连
MST[count] = graph[n].edgelink;//将此边放入MST数组
count++;
roots[vex_m] = vex_n; //将两个树合并,即将顶点vex_n作为vex_m的根节点
}
if (count == vex - 1) {
break;
}
}
}
for (int i = 0; i < vex - 1; i++)
{
printf("(%d,%d)%d\n", MST[i].startpoint, MST[i].endpoint, MST[i].weight); //打印最小生成树
}
return 0;
}
int vex = 12; //顶点个数
int edgeside = 12 * 12; //边个数
link graph[MAX_EDGE];
edge graphv2[MAX_EDGE];
/*
// for (int k = 0; k < edgeside; k++) {
// for (int n = 0; n <= 11; n++) {
// for (int m = 0; m <= 11; m++) {
// if (linkside[n][m].used == 0) {
// graph[k].startx = linkside[n][m].startx;
// graph[k].starty = linkside[n][m].starty;
// graph[k].endx = linkside[n][m].endx;
// graph[k].endy = linkside[n][m].endy;
// graph[k].lenth = linkside[n][m].lenth;
// graph[k].used = 1;
//
// graphv2[k].startpoint=n;
// graphv2[k].endpoint=m;
// graph[k].lenth=linkside[n][m].lenth;
// }
// }
// }
// }
*/
for (int n = 0; n < 144; n++) {
graph[n].used = 0;
}
//
int k = 0;
for (int n = 0; n <= 11; n++) {
for (int m = 0; m <= 11; m++) {
if (linkside[n][m].used == 0) {
graph[k].startx = linkside[n][m].startx;
graph[k].starty = linkside[n][m].starty;
graph[k].endx = linkside[n][m].endx;
graph[k].endy = linkside[n][m].endy;
graph[k].lenth = linkside[n][m].lenth;
graph[k].used = 1;
graph[k].edgelink.startpoint = n;
graph[k].edgelink.endpoint = m;
graph[k].edgelink.weight = linkside[n][m].lenth;
k++;
}
}
}
// 标记不用数据
for (int n = 0; n < MAX_EDGE; n++) {
if (graph[n].used == 0) {
graph[n].lenth = 999999;
graph[n].edgelink.weight = 999999;
}
}
// 插入排序
link max;
int index;
for (int n = 0; n < MAX_EDGE; n++) {
index = n;
max = graph[n];
for (int m = n + 1; m < MAX_EDGE; m++) {
if (graph[m].lenth < max.lenth) {
max = graph[m];
index = m;
}
}
graph[index] = graph[n];
graph[n] = max;
}
int roots[MAX_VEX]; //根数组,存放各顶点的根节点,以区别是否属于同一个集合
edge MST[MAX_EDGE]; //存放最小生成树(minimum spanning tree)
int count = 0;
for (int n = 0; n < MAX_VEX; n++) {
roots[n] = -1;
}
for (int n = 0; n < MAX_EDGE; n++) {
if (graph[n].used == 1) {
int vex_m = find_root(roots, graph[n].edgelink.startpoint);
int vex_n = find_root(roots, graph[n].edgelink.endpoint);
if (vex_m != vex_n) { //如果两者的根节点不同,说明他们属于不同的集合,可以相连
MST[count] = graph[n].edgelink;//将此边放入MST数组
count++;
roots[vex_m] = vex_n; //将两个树合并,即将顶点vex_n作为vex_m的根节点
}
if (count == vex - 1) {
break;
}
}
}
for (int k = 0; k < vex - 1; k++) {
// printf("(%d,%d)%d\n", MST[k].startpoint, MST[k].endpoint, MST[k].weight); //打印最小生成树
int start = MST[k].startpoint;
int end = MST[k].endpoint;
for (int n = 0; n < 10; n++) {
drawline(linkside[start][end].starty+n,
linkside[start][end].startx,
linkside[start][end].endy+n,
linkside[start][end].endx,
enemy[i].mapv3, 254, enemy[i].targetheight*pixnum, enemy[i].targetwidth*pixnum);
drawline(linkside[start][end].starty,
linkside[start][end].startx+n,
linkside[start][end].endy,
linkside[start][end].endx+n,
enemy[i].mapv3, 254, enemy[i].targetheight*pixnum, enemy[i].targetwidth*pixnum);
}
}
完整代码
//author @ bilibili 民用级脑的研发记录
// 开发环境 小熊猫c++ 2.25.1 raylib 版本 4.5
// 2024-7-14
// AABB 碰撞检测 在拖拽,绘制,放大缩小中
// 2024-7-20
// 直线改每帧打印一个点,生长的直线,直线炮弹
// 2024-8-4
// 实现敌人追击与敌人死亡与mapv2 敌人轨迹不绘制
#include <raylib.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define MAX_VEX 12
#define MAX_EDGE 144
// 重整原因:解决新函数放大缩小之下,raylib 的网格采样部分,选择数组的一部分刷新倒缓冲区里
// 从直接建立缓冲区,到先在数组里进行移动,然后再设置检查缓冲区
// 最大距离 - 当前坐标,实现坐标系变化,同时对应最顶上,变成新坐标下的最底下,可750-1=749数数得到
// 炮弹
typedef struct lineboom {
int playeriv2 = 0; // 一开始发射炮弹的玩家坐标
int playerjv2 = 0;
int drawiv2 = 0; // 发射目标位置坐标
int drawjv2 = 0;
int oldx = 0; // 记录上一格子,用于覆盖旧黑色点,产生炮弹轨迹
int oldy = 0;
int atking = 0; // 是否正在攻击,因为有好几个炮弹,命中之后就结束炮弹运行
int timev3 = 0; // 记录运行时间或者长度,到达位置,炮弹爆炸。v3是沿用time,和之前代码变量名字一样
// int toward = -1; // 朝向,在剥离代码发现不同朝向,直线代码不同,结束比较符号不同
int isboom = 0; // 是否到了爆炸的时机,在修改直线代码中发现的可以合并重复代码,产生的控制变量
} lineboom;
// 随机敌人
typedef struct target {
int targeti = 0; // 左上角网格坐标
int targetj = 0;
int targetwidth = 0; // 长宽
int targetheight = 0;
int islive = 0;
// RenderTexture2D* picture; // 敌人贴图
RenderTexture2D picture; // 敌人贴图
int** oldmap; // 局部复原数据
int** mapv3; // 像素也当成网格,每个记录像素是否能穿过
target* area; // 敌人内部的点
int arealenth; // 用于记录范围,lenth是半径
} target;
// 边
//typedef struct link {
// int startx; // 起点
// int starty;
// int endx; // 终点
// int endy;
// int used; // 是否已经使用
// int lenth; // 距离
//
//} link;
// 边
typedef struct edge {
int startpoint; // 起点在数组中的序号
int endpoint; // 终点在数组中的序号
int weight;
} edge;
// 边
typedef struct link {
int startx; // 起点的坐标
int starty;
int endx; // 终点的坐标
int endy;
int used; // 是否已经使用
int lenth; // 距离
edge edgelink; // 需要查点,记录所在数组位置
} link;
// 并查集查是否连通
int find_root(int roots[], int n) {
while (roots[n] != -1) {
n = roots[n];
}
return n;
}
// 检测碰撞,AABB碰撞检测,检测到碰撞时,碰撞产生矩形,左上角的坐标是 bangi j ,碰撞长宽是 bangwidth, bangheight
// 复制粘贴自碰撞检测
int bang(int drawi, int drawj, int mousewidth, int mouseheight, int targeti, int targetj, int targetwidth, int targetheight, int *bangi, int *bangj, int *bangwidth, int *bangheight) {
int isbang = 0; // 如果碰撞,就返回1
// +变- i 变 j
if (drawi >= targeti && targeti >= drawi - mouseheight) {
// 左上角重叠
if (targeti - targetheight <= drawi - mouseheight) {
if (drawj <= targetj && targetj <= drawj + mousewidth) {
// 左上角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < mouseheight - (drawi - targeti) ; i++) {
// for (int j = 0; j < mousewidth - ( targetj - drawj); j++) {
// map[targeti - i][targetj + j] = 2024;
// }
map[targeti - i][targetj] = 2024;
// }
// for (int j = 0; j < mousewidth - ( targetj - drawj); j++) {
// map[targeti][targetj + j] = 2024;
// }
// 左上角位置
*bangi = targeti;
*bangj = targetj;
// 长度,就是注释掉的循环的次数
*bangwidth = mousewidth - (targetj - drawj);
*bangheight = -(mouseheight - (drawi - targeti));
isbang = 1;
}
//被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < mouseheight - (drawi - targeti) ; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < targetwidth; j++) {
// map[targeti - i][targetj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = targetj;
// 注意负号,代表向下
*bangwidth = targetwidth;
*bangheight = -(mouseheight - (drawi - targeti));
isbang = 1;
}
} else if (targetj <= drawj && drawj <= targetj + targetwidth) {
// 右下角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < mouseheight - (drawi - targeti) ; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < mousewidth ; j++) {
// map[targeti - i][drawj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = drawj;
*bangwidth = mousewidth;
*bangheight = -(mouseheight - (drawi - targeti));
isbang = 1;
}
// //被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < mouseheight - (drawi - targeti) ; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < targetwidth - (drawj - targetj); j++) {
// map[targeti - i][drawj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = drawj;
*bangheight = -(mouseheight - (drawi - targeti));
*bangwidth = targetwidth - (drawj - targetj);
isbang = 1;
}
}
// for (int i = 0; i < mouseheight - (drawi - targeti) ; i++) {
// map[targeti - i][targetj] = 2024;
// }
}
//被包围了
else if (targeti - targetheight > drawi - mouseheight) {
// for (int i = 0; i < targetheight; i++) {
// map[targeti - i][targetj] = 2024;
// }
if (drawj <= targetj && targetj <= drawj + mousewidth) {
// 左上角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < targetheight; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < mousewidth - ( targetj - drawj); j++) {
// map[targeti - i][targetj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = targetj;
*bangwidth = mousewidth - (targetj - drawj);
*bangheight = -targetheight;
isbang = 1;
}
//被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < targetheight; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < targetwidth; j++) {
// map[targeti - i][targetj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = targetj;
*bangwidth = targetwidth;
*bangheight = targetheight;
isbang = 1;
}
} else if (targetj <= drawj && drawj <= targetj + targetwidth) {
// 右下角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < targetheight; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < mousewidth ; j++) {
// map[targeti - i][drawj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = drawj;
*bangwidth = mousewidth;
*bangheight = targetheight;
isbang = 1;
}
// //被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < targetheight; i++) {
map[targeti - i][targetj] = 2024;
// for (int j = 0; j < targetwidth - (drawj - targetj); j++) {
// map[targeti - i][drawj + j] = 2024;
// }
// }
*bangi = targeti;
*bangj = drawj;
*bangwidth = targetwidth - (drawj - targetj);
*bangheight = -targetheight;
isbang = 1;
}
}
}
} else if (targeti >= drawi && drawi >= targeti - targetheight) {
// 被包围了
if (targeti - targetheight <= drawi - mouseheight) {
// for (int i = 0; i < mouseheight ; i++) {
// map[drawi - i][targetj] = 2024;
// }
if (drawj <= targetj && targetj <= drawj + mousewidth) {
// 左上角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < mouseheight ; i++) {
map[drawi - i][targetj] = 2024;
// for (int j = 0; j < mousewidth - ( targetj - drawj); j++) {
// map[drawi - i][targetj + j] = 2024;
// }
// }
*bangi = drawi;
*bangj = targetj;
*bangwidth = mousewidth - ( targetj - drawj);
*bangheight = -mouseheight;
isbang = 1;
}
//被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < mouseheight ; i++) {
map[drawi - i][targetj] = 2024;
// for (int j = 0; j < targetwidth; j++) {
// map[drawi - i][targetj + j] = 2024;
// }
// }
*bangi = drawi;
*bangj = targetj;
*bangwidth = targetwidth;
*bangheight = -mouseheight;
isbang = 1;
}
} else if (targetj <= drawj && drawj <= targetj + targetwidth) {
// 右下角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < mouseheight ; i++) {
map[drawi - i][targetj] = 2024;
// for (int j = 0; j < mousewidth ; j++) {
// map[drawi - i][drawj + j] = 2024;
// }
// }
*bangi = drawi;
*bangj = drawj;
*bangwidth = mousewidth;
*bangheight = -mouseheight;
isbang = 1;
}
// //被包围了
else if (targetj + targetwidth < drawj + mousewidth) {
// for (int i = 0; i < mouseheight ; i++) {
map[drawi - i][targetj] = 2024;
// for (int j = 0; j < targetwidth - (drawj - targetj); j++) {
// map[drawi - i][drawj + j] = 2024;
// }
// }
*bangi = drawi;
*bangj = drawj;
*bangwidth = targetwidth - (drawj - targetj);
*bangheight = -mouseheight;
isbang = 1;
}
}
}
// //被包围了
else if (targeti - targetheight > drawi - mouseheight) {
// for (int i = 0; i < targetheight - ( targeti - drawi ); i++) {
// map[drawi - i][targetj] = 2024;
// }
if (drawj <= targetj && targetj <= drawj + mousewidth) {
// 左上角重叠
if (targetj + targetwidth >= drawj + mousewidth) {
// for (int i = 0; i < targetheight - ( targeti - drawi ); i++) {
map[drawi - i][targetj] = 2024;
// for (int j = 0; j < mousewidth - ( targetj - drawj); j++) {
// map[drawi - i][targetj + j] = 2024;
// }
// }
*bangi = drawi;
*bangj = targetj;
*bangwidth = mousewidth - ( targetj - drawj);
*bangheight = -(targetheight - ( targeti - draw