• C++_学习随笔_牛郎织女迷宫


    先上题目,

    这个题...我用C++写了200+行的代码,不包括数据纠错(比如输入点超过了迷宫的限制,或者输入数据时输入的不是整数)

    所以记录一下。

    C++ vector自带的方法比较少,而且感觉不是很好用,几乎所有用到的方法都是重新写的。

    我的思路是,已知牛郎的坐标(x1,y1) 然后织女的坐标(x2,y2)

    那么无论牛郎怎么走,一定要走m=|x1-x2|个横坐标,n=|y1-y2|个纵坐标(先不考虑封闭房间)

    并且路线一定是C(m+n,n)条(排列组合)。

    我使用0 表示牛郎在x轴上走了一步,用1 表示牛郎在y轴上走了一步。

    这样就能表示一条路径,比如牛郎在上图中的a点,织女在b点,那么 000111 就表示牛郎先向右走了3步,然后向下走了3

    当我们知道了两人的坐标后,也就知道了0的个数和1的个数,以上图为例,我们要求的路径就是 000111 这六个数字的无重复全排列。

    这样我们就知道了所有牛郎走向织女的可能路径。接下来就要排除被封闭房间所挡住的路径。

    以同样的方法,我们求出所有 牛郎通向封闭房间(在牛郎和织女之间的封闭房间)的路径,然后再删除 牛郎通向织女路径中 前部分与之重合的路径。

    以上图为例,我们找到了一条通向封闭房间的路径,0011接下来删除所有以 0011 开头的 牛郎通向织女的路径,然后重复这一过程,直至所有经过该封闭房间的路径都被删除,

    再以同样的方法检索剩余的封闭房间。

    最终剩下的,就是所有不经过封闭房间的 牛郎通向织女的路径。

    另,在求全排列这个地方卡住了好久,最终找到一种巧妙的算法并改了改。

    大概就是,先排出最小的路径,比如000111,然后从该数串的最后开始 ,选取两个数字进行比较,直到找到前一个数字比后一个数字小,在目前这个只有0 和1模型中就是找到“01”,

    然后将左边这个0与最靠后的1进行交换,比如001110,然后把原来0位置后面的所有元素翻转,最终变成001011。这就是仅大于000111的排列,按照上述方法不断重复,最终就能按照从小到大的顺序找全所有的 排列。

    我可能说的不太明白。我参考的是https://blog.csdn.net/morewindows/article/details/7370155中的非递归全排列方法。

    贴上代码:

      1 #include<iostream>
      2 #include<vector>
      3 #include<string>
      4 using namespace std;
      5 
      6 int min(int a, int b) {
      7     if (a < b)
      8         return a;
      9     else
     10         return b;
     11 }
     12 
     13 int max(int a, int b) {
     14     if (a > b)
     15         return a;
     16     else
     17         return b;
     18 }
     19 
     20 void Swap(int* a, int* b) {
     21     int temp;
     22     temp = *a;
     23     *a = *b;
     24     *b = temp;
     25 }
     26 
     27 void deleteVector(vector<vector<int>>& v, int i) {
     28     //删除v中第i条路径
     29     vector<int>* x, * y, temp;
     30     x = &v[i];
     31     y = x + 1;
     32     for (int n = 0; n < v.size() - i - 1; n++) {
     33         temp = *x;
     34         *x = *y;
     35         *y = temp;
     36         x++; y++;
     37     }
     38     v.pop_back();
     39 
     40 }
     41 
     42 void showVector(vector<int>v) {
     43     //打印一条路径
     44     for (int i = 0; i < v.size(); i++) {
     45         cout << v[i] << ",";
     46     }
     47     cout << endl;
     48 }
     49 
     50 void showVector(vector<vector<int>> v) {
     51     //打印所有路径
     52     for (int i = 0; i < v.size(); i++) {
     53         cout << "" << i + 1 << "条路线:";
     54         for (int j = 0; j < v[0].size(); j++) {
     55             cout << v[i][j] << ",";
     56         }
     57         cout << endl;
     58     }
     59 }
     60 
     61 void TurnLanguage(vector<vector<int>> v,string x,string y) {
     62     //转换成自然语言的路径
     63     for (int i = 0; i < v.size(); i++) {
     64         cout << "" << i + 1 << "条路线为: 从起始点开始-";
     65         for (int j = 0; j < v[0].size(); j++) {
     66             if(v[i][j]==0)
     67                 cout << x << "-";
     68             else
     69                 cout << y << "-";
     70         }
     71         cout << endl;
     72     }
     73 }
     74 
     75 void reverseVector(int* a, int* b) {
     76     //翻转 vector,vector自带的reverse老报错,没看出所以然来,所以重新写了个
     77     while (a < b) {
     78         Swap(a++, b--);
     79     }
     80 }
     81 
     82 void all_path(vector<int> first_path, vector<vector<int>>& allthepath) {
     83     //通过第一条路径 推算出所有路径
     84     bool hasnext = true;
     85     int* p, *q,*m,*the_end,counter=1;
     86     the_end = &first_path[first_path.size() - 1];
     87     m = &first_path[first_path.size() - 1];
     88     p = &first_path[first_path.size() - 1];
     89     q = &first_path[first_path.size() - 2];
     90 
     91     allthepath.push_back(first_path);
     92 
     93     while (hasnext) {
     94         if (*q >= *p) {
     95             //不触发
     96             q--; p--;
     97             if (p == &first_path[0]) {
     98                 hasnext = false;
     99                 break;
    100             }
    101         }
    102         else {
    103             //递增出现,触发,准备交换
    104             counter++;
    105             while (*m != 1) {
    106                 m--;
    107             }
    108             Swap(m, q);
    109             reverseVector(p, the_end);
    110             //cout << "find "<<counter<<" path!:          " ;
    111             //showVector(first_path);
    112             the_end = &first_path[first_path.size() - 1];
    113             m = &first_path[first_path.size() - 1];
    114             p = &first_path[first_path.size() - 1];
    115             q = &first_path[first_path.size() - 2];
    116             int reverse_counter = first_path.size() - 1;
    117             allthepath.push_back(first_path);
    118         }
    119 
    120     }
    121 }
    122 
    123 int main() {
    124     int row, column;
    125     int x_m, y_m, x_f, y_f;
    126     int boxes;
    127     int steps_x, steps_y;
    128     vector<int> boxes_x,boxes_y;
    129     
    130     cout << "Please input the row and column:" << endl;
    131     cin >> row>>column;
    132     cout << "Please input niulang'x_ord and y_ord:" << endl;
    133     cin >> x_m >> y_m;
    134     cout << "Please input zhinv'x_ord and y_ord:" << endl;
    135     cin >> x_f >> y_f;
    136     cout << "How many boxes do you want?";
    137     cin >> boxes;
    138     for (int i = 0; i < boxes; i++) {
    139         int temp_x, temp_y;
    140         cout << "Please input the x_ord and y_ord of " << i +1<< " box" << endl;
    141         cin >> temp_x >> temp_y;
    142         boxes_x.push_back(temp_x);
    143         boxes_y.push_back(temp_y);
    144     }
    145     steps_x = abs(x_m - x_f);
    146     steps_y = abs(y_m - y_f);
    147     //创建一个最小的数 作为第一条路径
    148     vector<int> thefirst_path;
    149     vector<vector<int>> solution;
    150     for (int i = 0; i < steps_x; i++) {
    151         thefirst_path.push_back(0);
    152     }
    153     for (int j = 0; j < steps_y; j++) {
    154         thefirst_path.push_back(1);
    155     }
    156     all_path(thefirst_path,solution);
    157     showVector(solution);
    158     //删除路线中被盒子挡住的
    159     for (int i = 0; i < boxes; i++) {
    160          //筛除不在路径上的盒子
    161         if (boxes_x[i]<=max(x_f,x_m)&&boxes_x[i]>=min(x_f,x_m)&&boxes_y[i]>=min(y_m,y_f)&&boxes_y[i]<=max(y_m,y_f)) {
    162             //记录所有牛郎通向盒子的路径
    163             int x_distance, y_distance;
    164             vector<int> firstpath_NiuAndBox;
    165             vector<vector<int>> paths_NiuAndBox;
    166             x_distance = abs(x_m - boxes_x[i]);
    167             y_distance = abs(y_m - boxes_y[i]);
    168             for (int j = 0; j < x_distance;j++) {
    169                 firstpath_NiuAndBox.push_back(0);
    170             }
    171             for (int j = 0; j < y_distance; j++) {
    172                 firstpath_NiuAndBox.push_back(1);
    173             }
    174             all_path(firstpath_NiuAndBox,paths_NiuAndBox);
    175             cout << "-----------"<<endl;
    176             showVector(paths_NiuAndBox);
    177             //删除牛郎通向织女的 且通过该盒子的路径
    178             int same_counter=0;
    179             for (int k = 0; k < paths_NiuAndBox.size(); k++) {
    180                 //先处理牛郎通向盒子的第k条路径
    181                 for (int u = 0; u < solution.size();u++) {
    182                     //与牛郎通向织女的第u条路径比较
    183                     same_counter = 0;
    184                     for (int v = 0; v < paths_NiuAndBox[0].size();v++) {
    185                         //通向盒子的 第k,v个元素与通向织女的第u,v个元素进行比较,如果全中,则删除该条牛郎通向织女的路径
    186                         if (paths_NiuAndBox[k][v] == solution[u][v]) {
    187                             same_counter++;
    188                         }
    189                         if (same_counter  == paths_NiuAndBox[0].size()) {
    190                             //全中,删除且u--
    191                             
    192                             deleteVector(solution,u);
    193                             u--;
    194                         }
    195                     }
    196                 }
    197             }
    198 
    199         }
    200         
    201     }
    202     cout << "---------------------" << endl;
    203     showVector(solution);
    204     cout << "---------------------" << endl;
    205     //转换成自然语言
    206     cout << "所以,可行方案如下:" << endl;
    207     string vector_x,vector_y;
    208     if (x_m > x_f)
    209         vector_x = "";
    210     else
    211         vector_x = "";
    212     if (y_m > y_f)
    213         vector_y = "";
    214     else
    215         vector_y = "";
    216 
    217     TurnLanguage(solution, vector_x, vector_y);
    218 }

    同时 输入为 (5,5) 行列 (这个行列我都没用到...)

    (4,1) 牛郎坐标

    (1,4) 织女坐标

      1            封闭房间个数

    (2,3) 封闭房间坐标

    的结果:

     

    第一块表示所有不考虑封闭房间的牛郎织女路径

    第二块表示牛郎到封闭房间的路径

    第三块表示 第一块去掉所有第二块开头的,也就是不经过该封闭房间的路径。

    最终转换为自然语言。

    感觉应该有更巧妙的方法,希望有大佬指正,我这代码也太多了。

  • 相关阅读:
    AJAX删除事件与加载数据
    AJAX的基本操作
    用JavaScript写弹窗
    jQuery事件和JSON点语法
    jQuery
    jQuery基础知识
    php 实现简单购物车功能(2)
    css实现3D立方体旋转特效
    for循环与foreach的区别
    微信小程序开发2 双线程模型,小程序中app.js中的生命周期,小程序的页面的生命周期,小程序的事件,事件补充(事件的冒泡,捕获)
  • 原文地址:https://www.cnblogs.com/reluctante1/p/12723751.html
Copyright © 2020-2023  润新知