人工智能作业-罗马尼亚度假问题(cug)

该代码实现了在OpenGL环境下,利用GLUT库进行交互,通过鼠标点击选择不同的路径搜索算法(A*、代价一致的宽度优先、贪婪算法)。代码具有简单的图形界面,但注释较少,可读性有待提高。程序会动态展示算法的搜索过程。
摘要由CSDN通过智能技术生成

一、运行环境

请安装vs与配置opengl环境,注意是glut,这上门课应该会同时上着计算机图形学,一般不变动的话,老师已经让配置了glut的环境。如果没有配置此环境,请百度或古狗。

二、代码

由于此前电脑坏了被迫刷机,又没有提前保存程序,目前剩下的只有代码,请自行创建项目,创建对应的cpp插入代码运行。

主函数与操作模块:Search.cpp

// SearchAI.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include"pch.h"
#include<windows.h>
#include"graph.h"
#include<stdlib.h>
#include<gl/glut.h>

Graph g;//定义


int k = 0;//控制选择三种算法


//初始化
void Initial()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//设置窗口背景颜色
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0, 800, 0.0, 600);
}
//


void mouseClick(int button,int state,int x,int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
    
        k = 1;//a*

    }
    if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
    {
        k = 2;//代价一致的宽度优先
    }
    if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
        k = 3;//贪婪算法
    }
}



void Display(void)
{
    
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0f, 0.0f, 0.0f);
    
    g.DrawGraph();//绘制图像

    glColor3f(1.0f, 0.0f, 0.0f);

    if (k == 1)
    {
        g.A_Star(0, 1);
    }
    if (k == 2)
    {
        g.Uniform_Cost_Search(0,1);
    }
    if (k == 3)
    {
        g.greedy(0, 1);
    }
    
    glFlush();
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(600, 100);
    //创建窗口,参数为窗口标题
    glutCreateWindow("鼠标左键a*--中键一致代价算法--右键贪婪算法");
    glutMouseFunc(mouseClick);
    glutDisplayFunc(Display);
    
    Initial();
    glutMainLoop();
    return 0;
}

以上便是主函数与操作运行模块,可以自行修改。

在这里我想说的是,当时由于时间匆忙,几乎是一个下午赶出来的代码,因此有如下问题:

1.注释少,可读性差.

2.为了让程序慢慢运行,实现直观的可视化,使用了睡眠函数,说实话有点哈皮.

3.代码写的稀烂.

不过好在非常的直观,可直接窥视了算法的运行流程。

在这里我要说一点,qt实际上是最tm方便好用的,当时只是因为我没用过qt和锻炼一下opengl能力才用的glut。

最后的重要代码如下:

graph.cpp

#pragma once

#include<windows.h>
#include<gl/glut.h>
#include<iostream>
#include<fstream>
#include<string>
#include<queue>
#include<vector>
#include <stdlib.h>
#include<ctime>
using namespace std;

//评估函数
int h[20] = { 366,0,160,242,161,176,77,151,226,244,241,234,380,98,193,253,329,80,199,374 };




#define _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS

//字符 ascll码
#define MAX_CHAR        128

//打印字符
void drawString(string str) {
    static int isFirstCall = 1;
    static GLuint lists;

    if (isFirstCall) { // 如果是第一次调用,执行初始化
                        // 为每一个ASCII字符产生一个显示列表
        isFirstCall = 0;

        // 申请MAX_CHAR个连续的显示列表编号
        lists = glGenLists(MAX_CHAR);

        // 把每个字符的绘制命令都装到对应的显示列表中
        wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
    }
    // 调用每个字符对应的显示列表,绘制每个字符
    int size = str.size();
    for (int i = 0; i < size; i++)
    {
        glCallList(lists + str[i]);
    }
}
//int转string类型
string IntToStr(int nVal)
{
    char intNumber[10];
    _itoa_s(nVal, intNumber, 10);
    string strValue(intNumber);
    return strValue;
}


int situation;//函数进行状况,控制节点的比较运算符重载,进而操控选择三种算法

//节点
class node
{
public:
    int num;//记录号
    int F, G, H;//f=g+h,g是节点到始节点的开销   f=g+h
    int parent;//记录父亲节点的编号
    string str;
    node(){
        num = 0;
        F = 0;
        G = 0;
        H = 0;
        parent = 0;
    }
    node(int p, int n){//构造函数,e为边长,p是父亲节点的下标,n是此节点下标
        num = n;
        parent = p;
        H = h[n];
    }

//运算符重载,在优先队列中,会根据此比较进行排列,由此弹出队列时可以取到权值最小的节点
    bool operator < (const node& a) const
    {
        if (0 == situation)//a*
        {
            return F > a.F;
        }
        if (1 == situation)//代价一致的宽度优先
        {
            return G > a.G;
        }
        if (2 == situation)//代价一致的宽度优先
        {
            return H > a.H;
        }
    }
};

//坐标
class Point
{
public:
    float x, y;//x,y坐标
    Point()
    {
        x = 0; y = 0;
    }
    void setPoint(float mx, float my)
    {
        x = mx; y = my;
    }

};

//绘制矩形
void DrawRec(Point p)
{
    glBegin(GL_LINE_LOOP);
    glVertex2f(p.x - 2, p.y - 2);
    glVertex2f(p.x + 2, p.y - 2);
    glVertex2f(p.x + 2, p.y + 2);
    glVertex2f(p.x - 2, p.y + 2);
    glEnd();
}

//绘制直线
void DrawLine(Point p1, Point p2)
{
    glBegin(GL_LINES);
    glVertex2f(p1.x, p1.y);
    glVertex2f(p2.x, p2.y);
    glEnd();
}

//图类,保存城市名称和边
class Graph
{
private:
    string city[20];//保存城市名称
    int edge[20][20];//邻接矩阵
    

public:
    Graph();
    Point p[20];//城市坐标
    void InitPoint();
    
    void InitGraph();//读入数据


    void Uniform_Cost_Search(int first, int end);//代价一致搜索

    void greedy(int first, int end);//贪婪算法

    void A_Star(int first, int end);//a*

    void DrawGraph();

};

Graph::Graph()
{
    InitGraph();
    InitPoint();
}


//读取文件
void Graph::InitGraph()
{
    ifstream ifs1("Romanian1.txt");
    //读入名字
    for (int i = 0; i < 20; i++)
    {
        ifs1 >> city[i];
    }
    ifs1.close();

    //读入矩阵
    ifstream ifs2("Romanian2.txt");
    for (int i = 0; i < 20; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            ifs2 >> edge[i][j];
        }
    }
    ifs2.close();
}

//设置坐标
void Graph::InitPoint()
{
    p[0].setPoint(5, 450);
    p[1].setPoint(420, 280);
    p[2].setPoint(258,240);
    p[3].setPoint(105, 250);
    p[4].setPoint(560, 190);
    p[5].setPoint(340,410);
    p[6].setPoint(400, 170);
    p[7].setPoint(530,326);
    p[8].setPoint(470, 490);
    p[9].setPoint(120,350);
    p[10].setPoint(130, 300);
    p[11].setPoint(326, 540);
    p[12].setPoint(90, 550);
    p[13].setPoint(360,320);
    p[14].setPoint(235,385);
    p[15].setPoint(200,420);//sibiu
    p[16].setPoint(15, 380);
    p[17].setPoint(460, 320);
    p[18].setPoint(500, 420);
    p[19].setPoint(50, 500);
}

//绘制地图
void Graph::DrawGraph()
{
    for (int i = 0; i < 20; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            DrawRec(p[i]);
            if ((0 != edge[i][j]) && (1000 != edge[i][j]))
            {
                DrawLine(p[i], p[j]);
                //打印边的数值
                float x = (p[i].x + p[j].x) / 2; float y = (p[i].y + p[j].y) / 2;//数字坐标
                int a = edge[i][j];
                string s = IntToStr(a);
                glRasterPos2f(x,y);
                drawString(s);
            }
        }
        //打印字符
        glRasterPos2f(p[i].x, p[i].y);
        drawString(city[i]);
    }
    glFlush();
    


}


//代价一致搜索
void Graph::Uniform_Cost_Search(int first, int end)
{
    vector<node> v;
    cout << "正在进行代价一致的宽度优先搜索" << endl;
    clock_t startTime, endTime;
    startTime = clock();//计时开始
    situation = 1;
    int searchNum = 0;//搜索的节点
    int generate = 1;//生成的节点
    int path[20] = { 0 };//用于记录已经遍历过的城市,0是未遍历,1是已经遍历
    if (first == end)
        return;
    //开始搜寻
    priority_queue <node> Q;//优先队列
    node temp(-1, 0);
    temp.G = 0; temp.parent = -1; temp.num = 0;
    temp.F = temp.G + temp.H;
    temp.str = city[first];
    Q.push(temp);
    while (!Q.empty())
    {
        temp = Q.top();//弹出栈顶元素,栈顶元素就是F最小的节点
        v.push_back(temp);
        Q.pop();
        if (temp.parent != -1)
        {
            Sleep(1000);
            glColor3f(1.0f, 0.0f, 0.0f);
            DrawLine(p[temp.num], p[temp.parent]);
            glFlush();
        }
        searchNum++;
        path[temp.num] = 1;//标记访问
        if (temp.num == end)
        {
            endTime = clock();//计时结束
            //打印路径
            int i = v.size() - 1;
            int k = v[i].num;
            int j = v[i].parent;//表示确定是下一个节点
            //从终点开始返回,打印边
            for (; i > 0;)
            {
                Sleep(500);
                i--;
                if (v[i].num == j)
                {
                    glColor3f(0.0f, 1.0f, 0.0f);
                    DrawLine(p[v[i].num], p[k]);
                    glFlush();
                    k = v[i].num;
                    j = v[i].parent;
                }
            }
            //输出路程
            cout << "代价一致的宽度优先搜索,结果如下" << endl << temp.str << endl << "  路径长度为:" << temp.G << endl;
            cout << "搜索节点数:" << searchNum << endl;
            cout << "生成节点数:" << generate << endl;
            cout << "运行时间: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
            return;
        }
        for (int i = 0; i < 20; i++)
        {
            //找到相邻节点,边长不是1000则相邻,不是0就是为了排除自身
            if (edge[temp.num][i] != 1000 && edge[temp.num][i] != 0)
            {
                if (path[i] != 1)
                {
                    node te(temp.num, i);//创建节点
                    ++generate;
                    te.G = edge[temp.num][i] + temp.G;
                    te.str = temp.str + "->" + city[i];
                    te.F = te.G + te.H;
                    if (te.parent != -1)
                    {
                        Sleep(300);
                        glColor3f(0.0f, 0.0f, 1.0f);
                        DrawLine(p[te.num], p[te.parent]);
                        Sleep(300);
                        glFlush();
                    }
                    Q.push(te);

                }
            }
        }
    }
}

void Graph::greedy(int first, int end)//贪婪算法
{
    vector<node> v;
    cout << "正在进行贪婪搜索" << endl;
    clock_t startTime, endTime;
    startTime = clock();//计时开始
    situation = 2;
    int searchNum = 0;//遍历的节点数
    int generate = 1;//记录生成的节点数目
    int path[20] = { 0 };//用于记录已经遍历过的城市,0是未遍历,1是已经遍历
    if (first == end)
        return;

    //开始搜寻
    priority_queue <node> Q;//优先队列
    node temp(-1, 0);
    temp.G = 0; temp.parent = -1; temp.num = 0;
    temp.F = temp.G + temp.H;
    temp.str = city[first];
    Q.push(temp);
    while (!Q.empty())
    {
        temp = Q.top();//弹出栈顶元素,栈顶元素就是F最小的节点
        v.push_back(temp);
        Q.pop();

        if (temp.parent != -1)
        {
            Sleep(1000);
            glColor3f(1.0f, 0.0f, 0.0f);
            DrawLine(p[temp.num], p[temp.parent]);
            glFlush();
        }
        searchNum++;
        path[temp.num] = 1;//标记访问
        if (temp.num == end)
        {
            endTime = clock();//计时结束
            //打印路径
            int i = v.size() - 1;
            int k = v[i].num;
            int j = v[i].parent;//表示确定是下一个节点
            for (; i > 0;)
            {
                Sleep(500);
                i--;
                if (v[i].num == j)
                {
                    glColor3f(0.0f, 1.0f, 0.0f);
                    DrawLine(p[v[i].num], p[k]);
                    glFlush();
                    k = v[i].num;
                    j = v[i].parent;
                }
            }
            //输出路程
            cout << "贪婪搜索,结果如下" << endl << temp.str << endl << "  路径长度为:" << temp.G << endl;
            cout << "搜索节点数:" << searchNum << endl;
            cout << "生成节点数:" << generate << endl;
            cout << "运行时间: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
            return;
        }
        for (int i = 0; i < 20; i++)
        {
            
            //找到相邻节点,边长不是1000则相邻,不是0就是为了排除自身
            if (edge[temp.num][i] != 1000 && edge[temp.num][i] != 0)
            {
                if (path[i] != 1)
                {
                    node te(temp.num, i);//创建节点
                    ++generate;
                    te.G = edge[temp.num][i] + temp.G;
                    te.str = temp.str + "->" + city[i];
                    te.F = te.G + te.H;
                    if (te.parent != -1)
                    {
                        Sleep(300);
                        glColor3f(0.0f, 0.0f, 1.0f);
                        DrawLine(p[te.num], p[te.parent]);
                        Sleep(600);
                        glFlush();
                    }
                    Q.push(te);
                }
            }
        }
    }
}




//a*寻路算法,first是起点下标,end是终点下标
void Graph::A_Star(int first, int end)
{
    vector<node> v;
    cout << "正在进行a*搜索" << endl;
    situation = 0;
    int generate = 1;
    int searchNum = 0;
    clock_t startTime, endTime;
    startTime = clock();//计时开始
    int path[20] = { 0 };//用于记录已经遍历过的城市,0是未遍历,1是已经遍历
    if (first == end)
        return;

    //开始搜寻
    priority_queue <node> Q;//优先队列
    node temp(-1, first);
    temp.G = 0; temp.parent = -1; temp.num = first;
    temp.F = temp.G + temp.H;
    temp.str = city[first];
    Q.push(temp);
    while (!Q.empty())
    {

        temp = Q.top();//弹出栈顶元素,栈顶元素就是F最小的节点
        v.push_back(temp);
        Q.pop();
        
        if (temp.parent != -1)
        {
            Sleep(500);
            glColor3f(1.0f, 0.0f, 0.0f);
            DrawLine(p[temp.num], p[temp.parent]);
            glFlush();
        }
        searchNum++;
        path[temp.num] = 1;//标记访问
        if (temp.num == end)
        {
            endTime = clock();//计时结束
            //打印路径
            int i = v.size() - 1;
            int k = v[i].num;
            int j = v[i].parent;//表示确定是下一个节点
            for (; i > 0;)
            {
                Sleep(1000);
                i--;
                if (v[i].num == j)
                {
                    glColor3f(0.0f, 1.0f, 0.0f);
                    DrawLine(p[v[i].num], p[k]);
                    glFlush();
                    k = v[i].num;
                    j = v[i].parent;
                }
            }
            //输出路程
            cout << "a*算法搜索,结果如下"<<endl << temp.str << endl<<"  路径长度为:" << temp.G << endl;
            cout << "搜索节点数:" << searchNum << endl;
            cout << "生成节点数:" << generate << endl;
            cout << "运行时间: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
            return;
        }
        for (int i = 0; i < 20; i++)
        {
            
            //找到相邻节点,边长不是1000则相邻,不是0就是为了排除自身
            if ((edge[temp.num][i] != 1000) && (edge[temp.num][i] != 0))
            {
                if (path[i] != 1)//若没有标记
                {
                    node te(temp.num, i);//创建节点
                    ++generate;
                    te.G = edge[temp.num][i] + temp.G;
                    te.str = temp.str + "->" + city[i];
                    te.F = te.G + te.H;
                    if (te.parent != -1)
                    {
                        Sleep(300);
                        glColor3f(0.0f, 0.0f, 1.0f);
                        DrawLine(p[te.num], p[te.parent]);
                        Sleep(600);
                        glFlush();
                    }
                    Q.push(te);
                }
            }
        }
        
    }
}




以上就是所有的代码了。实际上可以观察到,三种算法代码基本一致,只是评估函数的选择不同,

那为什么要写成这样呢?

因为这是完完全全赶出来的代码,当时混了好久,最后网上找不到,只好硬着头皮花了3个小时赶了出来。

希望用到此代码的人,可以自行看懂(写的稀烂,我现在已经看不懂了),然后若有时间的话,可以自己修修改改。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
信安综合实践是指信号安全综合实践课程,是中国地质大学(CUG)信号与信息处理专业的一门重要课程。此课程旨在通过理论与实践相结合的方式,培养学生的信息安全意识和实践能力。 信安综合实践主要涵盖以下几个方面。首先,课程通过介绍信息安全的基本知识以及网络威胁的类型和特点,提醒学生关注和重视信息安全问题。其次,课程通过实践项目,教导学生应对不同类型的网络攻击和安全漏洞的方法和技巧。学生将学习到如何使用各种安全工具和软件来保护计算机和网络系统的安全。同时,还会了解如何进行安全检测和防范措施的规划与实施。 信安综合实践还重视培养学生的团队合作和解决问题的能力。在项目实践中,学生需要组成小组,共同合作完成一些实际的安全任务,例如构建安全网络环境、开展网络安全漏洞检测、编写网络安全策略等。通过与同学的合作交流,学生可以锻炼自己的团队合作和沟通能力。 信安综合实践的开设有益于提高学生的信息安全意识和实践能力,培养他们成为具备信息安全知识与技巧的专业人才。这些专业人才在未来的工作中,可以为各种组织和企业提供安全保护和风险评估服务,促进网络安全环境的建设与发展。 总之,信安综合实践课程是中国地质大学的一门重要课程,通过理论与实践相结合的方式,培养学生的信息安全意识和实践能力。这将为他们未来的工作提供坚实的基础,并为网络安全行业的发展做出贡献。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值