记一次紧(you)张(dian)刺(wu)激(liao)的数学建模

  中国大学生数学建模竞赛,目前已成为全国高校规模最大的基础性学科竞赛,也是世界上规模最大的数学建模竞赛。      ——百度百科

  在每年的9月份会举行比赛,放出题目。这么高大上的比赛,本辣鸡抱着试一下的心态参与到其中。

  这个比赛在我们学校持续的周期还是挺长的,从未放假的7月份开始就要培训课程什么的,但是我小学期安排了STC的实验,而且明确要求不能请假,所以所有的培训课程都没有参加。咨询过老师后,我知道只要参与学校的模拟赛就有机会参与到最后的比赛,正巧,模拟赛是在暑假举行的,一共三次模拟,还有一个最终的仿真模拟。我和徐倩就尝试着做了第一次模拟比赛,提交了上去。然后就有了机会去参加下面的模拟。

  但是群里要求每个队伍都要是3个人,我们只有两个,需要找一个队友。这个我反正是不怎么着急,倒是徐倩催过我几次,尝试找了一下,没找到。日子一天天过着,这天有一位同学亲自来找我问我是否缺队友,她因为自己的队友士气不高弃他们而去,来到了我们这里,于是我们的队伍齐了,她叫袁欢,我们是一个社团的。在加入之前她问了我一个问题:你的另一个队友是女生吗?最后我们三个组合成一个队伍了。然后放假了,袁欢回家,徐倩去了三下乡队伍(两周),我去了中科大(一周)。连面基都没有,就这样放假了。

  我从中科大回来后几天,第二次模拟差不多开始了,那时候正好是徐倩的三下乡要结束的时候。我们就开始了做这次的题目,选了一个对数据处理要求较高的地震预测。接下来的过程也很明显,我们不行,沟通不畅,技能掌握较差,草草做了这次的题,几乎都是袁欢自己一个人做的吧,但是我也做了不少。然后就是联系不太上徐倩,原来是那两天她一直在车上,三下乡会学校,学校回家,模拟结束在她回家的途中,就这样,第二次模拟结束了。结束后,徐倩说退队了,没有理由,袁欢说我们什么事都不跟她说,她也走了,去找了她老队友,我又成了孤家寡人。不过,没什么事,本来就是抱着试一下的心态来的,我的期望本就没有那么高,就这样解散了。

  解散以后,还像大一暑假在寝室里一样,刷剧,上次看完了权力的游戏,这次看完了行尸走肉,当然,其中还穿插着学习游泳、学习知识的过程。浑浑噩噩吧,跟我预想的暑假是不一样的。然后在8月20号左右,突然有一个队伍问了是否还有散人没组队,他们联系不上了另一个队友了,然后我就去了。于是倪卓颖、候彦卉、张虎威又组了一个队伍。第三次模拟被我水过去了,最终模拟之前有一个答辩,我们见了一面,就这样,我们等着最后一次的模拟的到来。到了以后,我们一起做了一天的题,后面两天我就回家了。这一天我么将解题思路定了下来,选的是船调度的问题,用程序强行模拟,结果是能做出来的,虽然过程不太好看,但是有了解题思路。接下来的事情就是他俩一起处理的,我回家。他俩很棒,处理的很好,最后模拟也按时提交了。答辩什么的我没去,都是她俩完成的。

  下面就是开学了,最后的国赛报名。原来,只要坚持到最后,所有的队伍都可以报名,并没有筛掉队伍,队伍数目从130+到80+,纯粹是队伍不想参加而已,根据老师的指示,我们成功报名参赛。并在9月13日到9月16日规定的时间内去完成比赛。重头戏也就上来了。

  比赛开始了,当天晚上,我们三个人在综合楼302一起找资料,分析题目等等事情,最终确定出选题,最后选的是B题,RGV小车的智能调度。我理解的这道题目是要CNC仪器工作的时间够长,等待时间越少越好,我是这么想的,既然小车有自己的运动方式,CNC也有自己的工作状态选择,那么也就是说只要搞清楚两者之间的联系,然后在整个8小时内进行合理调度,防止CNC需求的撞车就可以达到我认为的目的,是的,我的想法很简单,自己设计出一套CNC和RGV一起运动的状态,一直运行就行。然后,去网上搜一下车间、小车之类的论文,得到的结果都差不多是使用遗传算法去求解、利用模拟退火的方法找到全局最优值,按照这个最优值去运行流水线等。

  卧槽,这是什么?遗传算法、模拟退火?之前有过耳闻,但是完全没有尝试过,而且百度了知识点以后,基础知识就够喝一壶的,三天时间内哪有那么多时间,而且我觉得这个算法并不适合B题的场景,怎么套入这个算法也是一件麻烦的事情,卧槽,这可怎么办,凉了啊。到了14日的上午10点,我决定不使用什么遗传和退火了,根本做不出来,然后按照自己的思路进行模拟,将机器流水线的运行情况模拟出来得到数据填入到表格中。

  强行模拟的实现我使用了优先队列这种数据结构,然后在模拟的过程中我确定一种选取需求的方法,一个需求直接去需求的位置,多个需求的话,将所有需求进行排队,离得比较近的先访问,以秒为时间进行递增,这样去模拟,虽然感觉没什么用,但是也没有其他的办法了。强行做了一遍,下面是我的代码

//365

#include <iostream>
#include<queue>
#include<cmath>
#include <fstream>
using namespace std;

const int RGV_1 = 20;            //rgv移动需要的时间
const int RGV_2 = 33;
const int RGV_3 = 46;
const int CNC_WORK = 560;       //cnc加工完成的时间
const int RGV_WORK_JI = 28;     //奇数cnc上下料
const int RGV_WORK_OU = 31;     //偶数cnc上下料
const int clean = 25;            //清洗时间
int wuliao_bianhao = 9;

struct cnc{
    int bianhao_cnc;            //cnc仪器的编号
    int bianhao_wuliao;         //物料编号
    int time_begin;             //开始时间
    int time_end;               //结束时间
    int distan;                 //距离grv的距离
    bool xuqiu;                 //需求信号
    bool wuliao;                //是否有物料
    void init_cnc(int i){       //初始化
        bianhao_cnc = i;
        bianhao_wuliao = 0;
        time_begin = 0;
        time_end = 0;
        distan = 0;
        xuqiu = true;
        wuliao = false;
    }
    friend bool operator< (cnc c1,cnc c2){
        if(c2.distan < c1.distan) return true;
        else if(c1.distan == c2.distan && c2.bianhao_cnc < c1.bianhao_cnc) return true;
        return false;
    }
};

struct grv{
    int weizhi;                 //rgv的位置
    bool work;                  //上下料
    bool clea;                  //清洗信号
    bool wait;                  //等待信号
    void init_grv(){            //初始化
        weizhi = 1;
        work = false;
        wait = true;
        clea = false;
    }
};

void Init(cnc c[],grv g){       //初始上料的状态
    c[1].bianhao_wuliao = 1;
    c[1].time_begin = 1;
    c[1].time_end = 59*4+20*3;
    c[1].distan = 3;
    c[1].xuqiu = false;
    c[1].wuliao = true;
    c[2].bianhao_wuliao = 2;
    c[2].time_begin = 29;
    c[2].time_end = 59*4+20*3;
    c[2].distan = 3;
    c[2].xuqiu = false;
    c[2].wuliao = true;
    c[3].bianhao_wuliao = 3;
    c[3].time_begin = 80;
    c[3].time_end = 59*4+20*3;
    c[3].distan = 2;
    c[3].xuqiu = false;
    c[3].wuliao = true;
    c[4].bianhao_wuliao = 4;
    c[4].time_begin = 80+28;
    c[4].time_end = 59*4+20*3;
    c[4].distan = 2;
    c[4].xuqiu = false;
    c[4].wuliao = true;
    c[5].bianhao_wuliao = 5;
    c[5].time_begin = 128+31;
    c[5].time_end = 59*4+20*3;
    c[5].distan = 1;
    c[5].xuqiu = false;
    c[5].wuliao = true;
    c[6].bianhao_wuliao = 6;
    c[6].time_begin = 128+28+31;
    c[6].time_end = 59*4+20*3;
    c[6].distan = 1;
    c[6].xuqiu = false;
    c[6].wuliao = true;
    c[7].bianhao_wuliao = 7;
    c[7].time_begin = 128+48+31+31;
    c[7].time_end = 59*4+20*3;
    c[7].distan = 0;
    c[7].xuqiu = false;
    c[7].wuliao = true;
    c[8].bianhao_wuliao = 8;
    c[8].time_begin = 128+48+31+28+31;
    c[8].time_end = 59*4+20*3;
    c[8].distan = 0;
    c[8].xuqiu = false;
    c[8].wuliao = true;
    g.clea = false;
    g.wait = false;
    g.weizhi = 4;
    g.work = false;
}

int time_daolu(cnc c,grv &g){                            //计算出上下料需求需要的时间
    if(c.distan == 0){
        g.weizhi = (c.bianhao_cnc+1) >> 1;
        return 0;
    }
    else if(c.distan == 1){
        g.weizhi = (c.bianhao_cnc+1) >> 1;
        return RGV_1;
    }
    else if(c.distan == 2){
        g.weizhi = (c.bianhao_cnc+1) >> 1;
        return RGV_2;
    }
    else{
        g.weizhi = (c.bianhao_cnc+1) >> 1;
        return RGV_3;
    }
}
int time_fangxiang(cnc c){
    if(c.bianhao_cnc%2 == 1) return RGV_WORK_JI;
    return RGV_WORK_OU;
}
void gengxin_time(cnc s,cnc c[],grv &g, int dl,int x){         //更新时间    x总时间  time没加清洗时间
    for(int i = 1; i < 9; i++){
        if(s.bianhao_cnc == c[i].bianhao_cnc){
            c[i].bianhao_wuliao = wuliao_bianhao;
            wuliao_bianhao++;
            c[i].time_begin = s.time_end+dl;
            c[i].time_end = x;
            c[i].distan = 0;
            c[i].xuqiu = false;
            c[i].wuliao = true;
        }
        else{
            c[i].time_end = x;
        }
    }
    g.clea = false;
}

void gengxin_dis(cnc c[],grv &g){                                //更新cns距grv的距离
    for(int i = 1; i < 9; i++){
        c[i].distan = abs(((i+1)>>1) - g.weizhi);
    }
}

void gengxin_xuqiu(cnc c[]){
    for(int i = 1; i < 9; i++){
        c[i].xuqiu = false;
    }
}

int main()
{
    ofstream outfile;
    outfile.open("结果.txt");

    int count = 1;
    cnc c[9];
    grv g;
    for(int i = 1; i < 9; i++){
        c[i].init_cnc(i);
    }
    g.init_grv();
    Init(c,g);
    count += (27+32)*4+18*3;
    priority_queue<cnc>cn;
    while(count <= 28800){
        for(int i = 1; i < 9; i++){
            int xy = (i%2==0)?RGV_WORK_OU:RGV_WORK_JI;
            if(!c[i].xuqiu && ((c[i].time_end-c[i].time_begin) >= (CNC_WORK+xy))){
                c[i].xuqiu = true;
                cn.push(c[i]);
            }
        }
        if(!cn.empty()){
            cnc stem = cn.top();
            outfile << stem.bianhao_wuliao << " " << stem.bianhao_cnc << " " << stem.time_begin << " ";
            cn.pop();
            int dl = time_daolu(stem,g);
            int fx = time_fangxiang(stem);
            outfile << stem.time_end+dl << endl;
            count += dl+fx+clean;
            gengxin_time(stem,c,g,dl,count);
            gengxin_dis(c,g);
            while(!cn.empty()) cn.pop();
            gengxin_xuqiu(c);

        }
        else{
            count++;
            for(int i = 1; i < 9; i++){
                c[i].time_end++;
            }
        }
    }
    cout << wuliao_bianhao-1;
    outfile.close();
    return 0;
}

  紧赶慢赶,这个不算是很复杂的代码算是完成了,而且根据题目难度的增加,调整相应的细节可以得出一些数据,例如两个队列啊,价格随机故障啊这样的,数据可以弄出来了,填进去就ok了,即使这个数据是没用的,也是我们自己做出来的。

  其中还有一个事,写代码这个事情真的不简单啊。就这个这么简单的代码,当然包括他的一点升级版,花了我两天整去写,最后一晚,就为了加一个随机数,折腾了一夜,一把老骨头也是拼了,第二天早中晚都没吃饭,直到提交上去才松口气。

  紧张刺激。努力写代码,努力学习,什么都不会的自己真的太菜了。

posted @ 2018-09-19 13:44  琥琥笙威  阅读(372)  评论(0编辑  收藏  举报