首页 > 代码库 > 火车车厢重排问题

火车车厢重排问题

2014-11-04

主要数据结构:栈

题目:一列火车要将n节车厢分别送往n个车站按1~n的次序编号,火车按照n,n-1,…1的编号次序经过车站。假设车厢的编号就是其目的地车站的编号。

要求:给定一个任意的车厢排列次序。重新排列车厢,使其按照从1到n的次序排列。规定重排时,只能从入轨到缓冲铁轨,或者从缓冲铁轨到出轨。

总的思路

首先:将所需要重排的车厢编号从左到右依次输入数组carrage中;

然后:对carrage中的元素进行从左往右逐个遍历,如果符合下一个输出,则直接将其输出,并且遍历所有的缓冲轨道,查找是否有符合下一个输出的车厢,有的话便将其输出,否则将其压入缓冲轨道

未经优化的代码:

  1 #include <iostream>  2 #include <stack>  3 using namespace std;  4   5 stack<int> stack_final;  6   7   8 void Output(int& minH, int& minS, stack<int> H[], int k, int n) {  9     // put the car from the strack to the output line, and change the minH and minS 10     int index; // the index of the car 11     //delete the minist car number from the minS 12     stack_final.push(H[minS].top()); 13     H[minS].pop(); 14     cout << "Move car " << minH << "from holding track " << minS << " to output line" << endl; 15     //serch all the track‘s top, find the new minH and minS 16     minH = n+2; 17     for (int i= 0; i < k; i++) { 18         if (!H[i].empty() && (index = H[i].top()) < minH) { 19             minH = index; 20             minS = i; 21         } 22     } 23 } 24  25 bool Input(int c, int& minH, int& minS, stack<int> H[], int k, int n) { 26     // put the new car c into the track 27     // if there is no available track, then return false, else return true 28         // find the best track for the car c 29         // initial 30     int BestTrack = 0; //the best track now 31     int BestTop = n+1; //the best track‘s top car 32     int index; //the index for the car 33     // search the k track 34     for (int i= 0; i < k; i++) { 35         if (!H[i].empty()) { 36             index = H[i].top(); 37             if (c < index && index < BestTop) { 38                 //the top car‘s number is the smallest 39                 BestTop = index; 40                 BestTrack = i; 41             } 42         } else { // the track is empty 43             if (!BestTrack) { 44                 BestTrack = i; 45             } 46         } 47     } 48     if (!BestTrack) { 49             return false; //there is available track to use 50     } 51     H[BestTrack].push(c); 52     cout << "Move car " << c << "from input to holding track " << BestTrack << endl; 53     //if it is essencial, then change the minH and minS 54     if (c < minH) { 55         minH = c; 56         minS = BestTrack; 57     } 58     return true; 59 } 60  61 bool Railroad(int input[], int n, int k) { 62     //k  63     // if it resort succed, then return true, else return false 64         // create the stack according to the k 65     stack<int> *H; 66     H = new stack<int> [k]; 67     int NowOut = 1; // the next number of car to putout 68     int minH = n+1; //the minist number car in the k 69     int minS; //the minist number‘s strack 70         // resort the car 71     for (int i = n-1; i >= 0; i--) { 72         int number = input[i]; 73         if (number == NowOut) { 74             cout << "Move car " << number << " from the input line to the output line\n"; 75             stack_final.push(number); 76             NowOut++; 77             while (minH == NowOut) { 78                 Output (minH, minS, H, k, n); 79                 NowOut++; 80             } 81         } else { 82             int end = 0; 83             for (int j = i; j > 0; j--) { 84                 if (input[j-1] < input[j]) { 85                     end = j; 86                     break; 87                 } 88             } 89             for (int j = end; j <= i; j++) { 90                 if (!Input (input[j], minH, minS, H, k, n)) { 91                     return false; 92                 } 93             } 94             if (end) { 95                 i = end; 96             } 97         } 98     } 99     return true;100 }101 102 int main() {103     int n, *input;104     cin >> n;105     input = new int[n];106     for (int i = 0; i < n; i++) {107         cin >> input[i];108     }109     if (Railroad(input, n, n-1)) {110         cout << "resort succed!\n";111         while (!stack_final.empty()) {112             cout << stack_final.top() << " ";113             stack_final.pop();114         }115     } else {116         cout << "failed\n";117     }118 }
View Code

经过优化之后的代码:
增加的条件:车厢可以从排在后面的缓冲轨道移到前面的缓冲轨道。

优化算法

1:压入缓冲轨道:

首先:以要入栈的车厢为始端,遍历carrage,找到一段连续递增的序列,如果没有连续递增序列,则只将该车厢压入缓冲轨道,否则,将该段递增序列压入到缓冲轨道

只有一个车厢等待压入缓冲轨道:遍历所有的缓冲轨道,查找栈顶元素编号大于并且最接近该车厢编号,若有符合条件的轨道,则直接压入,否则创建一个新的空轨道用作该车厢的缓冲轨道。并且对所有缓冲轨道的车厢进行调整,以最接近且上面小于下面为原则。

有一段连续递增序列车厢等待压入缓冲轨道:采用一个临时栈,一个目标栈,利用“倒水”的方法将该段递增序列压入缓冲轨道,与此同时,为每一个寻找最优轨道。

2:每一次将车厢送入缓冲轨道之后,都对缓冲轨道进行一遍优化。

  1 #include<iostream>  2 #include<stack>  3 using std::stack;  4 using std::cin;  5 using std::cout;  6   7 const int MAX = 100;  //缓冲栈的最大数目  8 const int INF = 0x7fffffff;  9  10 class trainDispatch{ 11     public: 12         trainDispatch();  //读入待排序的车厢编号数目和车厢编号,并储存在carrage[]中 13         void solution();  //对待排序的车厢进行排序并不断输出 14     private: 15         stack<char> stackArray[MAX];  //缓冲栈 16         int carrageNum;  //储存车厢数  17         int usedStackNum;  //已经使用过的缓冲轨道数 18         int carrage[MAX];  //原始车厢序列 19         int expectNum;  //待输出的车厢编号 20          21         int findIncrementEnd(int start);  //找到carrage[start]开始的最大的递增项,返回其索引 22         int findFirstEmpty(int st, int ed);  //找到第一个空的缓冲轨道  23         int findNearestBigger(int x, int st, int ed);  //遍历st到ed之间的缓冲轨道,寻找大于且最接近x的缓冲轨道编号,若存在,返回该轨道编号,否则,返回-1.  24         void move (int stIndex, int edIndex, int tempStack, int inStack);  //以tempStack为临时缓冲栈编号,inStack为目标栈编号,将stIndex到edIndex之间的车厢编号压                                                                              入inStack 25         int findLargestTop(int st, int ed);  //遍历编号介于st与ed之间的缓冲轨道,寻找栈顶元素最大的轨道编号 26         int findLargestLessThan(int index, int st, int ed);  //遍历编号介于st与ed之间的缓冲轨道,寻找栈顶元素最大且小于编号为index轨道的栈顶元素的轨道编号 27          28         void MoveInSingle(int Index);  //只将编号为carrage[index]的车厢压入缓冲轨道 29         void MoveInMoreThanOneSimple(int startIndex, int endIndex);  //将车厢编号从carrage[startIndex]到carrage[endIndex]的连续递增轨道压入缓冲轨道 30         void MoveInMoreThanOneComplex(int startIndex, int endIndex);  //将车厢编号从carrage[startIndex]到carrage[endIndex]分为连续递增段并压入缓冲轨道 31         void MoveOut(int&);  //遍历所有的缓冲轨道,若有符合下一个输出的元素,则将其输出 32         void adjust(int st, int ed);  //对缓冲轨道进行优化 33 }; 34  35 /*  输入所需要重排的车厢数目和车厢序列/ 36     车厢序列的读取方法为从左往右 */ 37 trainDispatch::trainDispatch() { 38     usedStackNum = 0;    cout << "please enter the number of the carrages:\n"; 39     cin >> carrageNum; 40     cout << "please enter the serial number in order\n"; 41     for (int i = 0; i < carrageNum; i++) { 42         cin >> carrage[i]; 43     } 44 } 45  46 void trainDispatch::solution() { 47     int ed; 48     int expectNum = 1; 49     /* 从左往右依次遍历车厢号,若不符合输出,则将车厢号压入缓冲轨道/ 50     否则,将其输出,并遍历各个缓冲轨道,查询是否有符合条件的输出*/ 51     for (int i = 0; i < carrageNum ; i++) { 52         if (carrage[i] != expectNum) { 53             ed = findIncrementEnd(i);  //判断该车厢与其后面排列的车厢是否为递增关系,若不是则只将该车厢压入缓冲轨道 54                                       // 否则将该串递增序列压入缓冲轨道 55             if (ed == i) {  //无递增关系 56                 MoveInSingle(i); 57             } else {  //i 到 ed之间为递增 58                 MoveInMoreThanOneComplex(i, ed); //将i-ed之间的元素压入缓冲轨道 59                 i = ed; 60             } 61         } else { 62             cout << "the carrage-" << carrage[i] << " move straightly, doesn`t move into any stack\n"; 63             expectNum++; 64             MoveOut(expectNum);  //遍历所有的缓冲轨道,查找是否有符合下一个输出 65         } 66         adjust(0, usedStackNum-1);  //遍历所有的缓冲轨道,根据轨道的栈顶元素,对轨道进行优化 67     } 68 } 69  70 /*寻找以carrage[start]为始的递增序列,返回最大项的索引ed*/ 71 int trainDispatch::findIncrementEnd(int start) { 72     int ed = start; 73     while (carrage[ed] < carrage[ed+1]) { 74         ed++; 75     } 76     return ed; 77 } 78  79 /*寻找st到ed之间的第一个空栈,返回空栈的索引i*/ 80 int trainDispatch::findFirstEmpty(int st, int ed) { 81     int i = st; 82     for (i = st; i <= ed; i++) { 83         if (stackArray[i].empty()) { 84             break; 85         } 86     } 87     return i; 88 } 89  90 /* 遍历所有的缓冲轨道,寻找与所要入栈的元素x最接近且大于该元素的符合条件的缓冲轨道,返回该轨道的索引munNum*/ 91 int trainDispatch::findNearestBigger(int x, int st, int ed) { 92     int i; 93     int min = INF; 94     int minNum = -1; 95     for (i = st; i <= ed; i++) { 96         if (!stackArray[i].empty() && stackArray[i].top() > x) { 97             if (min > stackArray[i].top()-x) { 98                 min = stackArray[i].top()-x; 99                 minNum = i;100             }101         }102     }103     return minNum;104 }105 106 /*遍历编号介于st与ed之间的缓冲轨道,寻找栈顶元素最大且小于编号为index轨道的栈顶元素的轨道编号,返回该轨道编号num*/107 int trainDispatch::findLargestLessThan(int index, int st, int ed) {108     int num = -1;109     int largest = 0;110     for (int i = st; i <= ed; i++) {111         if (!stackArray[i].empty() && stackArray[i].top() < stackArray[index].top())112             if (largest < stackArray[i].top()) {113                 largest = stackArray[i].top();114                 num = i;115             }116     }117     return num;118 }119 120 /*将carrage[stIndex]与carrage[edIndex]之间的元素压入栈;121   tempStack作为临时栈的编号,inStack作为目标栈的编号*/122 /*将递增车厢从stIndex~edIndex-1先压入一个缓冲栈stackArray[tempStack],123   将最大项直接压入目标栈stackArray[inStack]*/124 /*逐个遍历缓冲栈stackArray[tempStack]中的元素,并将其压入最优缓冲轨道125   对于缓冲栈最后一个元素,考虑可能将其压回该缓冲栈的情况*/126 void trainDispatch::move (int stIndex, int edIndex, int tempStack, int inStack) {127     for (int i = stIndex; i < edIndex; i++) {128         stackArray[tempStack].push(carrage[i]);129         cout << "the carrage-" << carrage[i] << " move into the stack-" << tempStack+1 << "\n";130     }131     stackArray[inStack].push(carrage[edIndex]);132     cout << "the carrage-" << carrage[edIndex] << " move into the stack-" << inStack+1 << "\n";133     for (int i = edIndex-1; i > stIndex; i--) {134         int temp = stackArray[tempStack].top();135         stackArray[tempStack].pop();136         int in = findNearestBigger(temp, tempStack+1, usedStackNum-1);137         stackArray[in].push(carrage[i]);138         cout << "the carrage-" << carrage[i] << " move out of stack-" << tempStack+1139              << ", then move in the stack-" << in+1<< "\n";140     }141 142     stackArray[tempStack].pop();143     int in = findNearestBigger(carrage[stIndex], tempStack, usedStackNum-1);144     stackArray[in].push(carrage[stIndex]);145     if (in != tempStack) {146         cout << "the carrage-" << carrage[stIndex] << " move out of stack-" << tempStack+1147              << ", then move in the stack-" << in+1<< "\n";148     }149 }150 151 /*遍历编号st到ed间的缓冲轨道,寻找栈顶车厢编号最大的栈,返回该栈的索引num*/152 int trainDispatch::findLargestTop(int st, int ed) {153     int num = -1;154     int largest = 0;155     for (int i = st; i <= ed; i++) {156         if (! stackArray[i].empty()) {157             if (largest < stackArray[i].top()) {158                 largest = stackArray[i].top();159                 num = i;160             }161         }162     }163     return num;164 }165 166 /*只将一个车厢压入缓冲轨道*/167 /*在所有的缓冲轨道中找不到比要入栈元素更大的栈;则寻找第一个空栈*/168 /*若原有栈的数目不够,即没有空栈,则再创建一个空栈*/169 void trainDispatch::MoveInSingle(int Index) {170     int emptyIndex;171     int in = findNearestBigger(carrage[Index], 0,usedStackNum-1);172     if (in == -1) {  173         emptyIndex = findFirstEmpty(0, usedStackNum-1);174         if (emptyIndex >= usedStackNum) { 175             usedStackNum++;176         }177         stackArray[emptyIndex].push(carrage[Index]);178         cout << "the carrage-" << carrage[Index] << " move into the stack-" << emptyIndex+1 << "\n";179     } else {180         stackArray[in].push(carrage[Index]);181         cout << "the carrage-" << carrage[Index] << " move into the stack-" << in+1 << "\n";182     }183 }184 185 /*将连续递增的车厢压入缓冲轨道*/186 /*遍历所有缓冲轨道,若有符合条件的非空栈,则将其作为目标栈187   否则,寻找空栈作为目标栈*/188 void trainDispatch::MoveInMoreThanOneSimple(int startIndex, int endIndex) {189     int in = findNearestBigger(carrage[endIndex], 0, usedStackNum-1);190     if (in > 0 && in < usedStackNum) {191         move(startIndex, endIndex, 0, in);192     }193     if (in == -1) {194         int firempty = findFirstEmpty(0, usedStackNum-1);195         if (firempty == usedStackNum) {  //所用过的栈中无空栈 196             //用过的栈的数目为0197             if (usedStackNum == 0) {198                 usedStackNum+=2; //创建两个新栈,一个作为临时缓冲栈,一个作为目标栈199                 move(startIndex,endIndex, 0, 1);200             } else {  //用过的栈不为空,且用过的栈的数目大于0 201                 usedStackNum++;202                 move(startIndex,endIndex, 0, usedStackNum-1);203             }204         } else {  //所用过的栈中有空栈205             if (firempty == 0) {  //第一个是空栈 206                 int secEmpty = findFirstEmpty(firempty+1, usedStackNum-1); //再次寻找另一个空栈207                 if (secEmpty == usedStackNum) {208                     usedStackNum++;209                 }210                 move(startIndex,endIndex, firempty, secEmpty);211             } else {212                 move(startIndex,endIndex, 0, firempty); //第一个不是空栈,将第一个作为临时缓冲栈213             }214         }215     }216     if (in == 0) {217         in = findNearestBigger(carrage[endIndex], 1, usedStackNum-1);218         if (in >= 1 && in < usedStackNum) {219             move(startIndex, endIndex, 0, in);220         } else {221             int firempty = findFirstEmpty(1, usedStackNum-1);222             if (firempty == usedStackNum) {223                 usedStackNum++;224             }225             move(startIndex,endIndex, 0, firempty);226         }227     }228 }229 230 /*将递增序列车厢压入缓冲轨道*/231 /*将该段递增序列不同的连续递增段*/232 /*例如:原缓冲轨道中有编号6的车厢,待压入的递增序列为34578,此时以6位界限,将其分为345和78分别压入缓冲轨道*/233 void trainDispatch::MoveInMoreThanOneComplex(int startIndex, int endIndex) {234     int div;235     int in;236     for (div = endIndex; div >= startIndex; div--) {237         in = findNearestBigger(carrage[div], 0, usedStackNum-1);238         if (in > 0 && in < usedStackNum) {239             if (startIndex == div) {240                 MoveInSingle(div);241             } else {242                 MoveInMoreThanOneSimple(startIndex, div);243             }244             if (div+1 == endIndex) {245                 MoveInSingle(endIndex);246             }247             if (div+1 < endIndex) {248                 MoveInMoreThanOneSimple(div+1, endIndex);249             }250             break;251         }252     }253     if (div < startIndex) {254         MoveInMoreThanOneSimple(startIndex, endIndex);255     }256 }257 258 /*遍历所有的缓冲轨道,将符合下一个输出条件的车厢输出至出轨*/259 void trainDispatch::MoveOut(int& expectNum) {260     bool con = true;261     while (con) {262         con = false;263         for (int k = 0; k < usedStackNum; k++) {264             if (!stackArray[k].empty()) {265                 if (stackArray[k].top() == expectNum) {266                     con = true;267                     stackArray[k].pop();268                     cout << "the carrage-" << expectNum << " move out of the stack-" << k+1 << "\n";269                     expectNum++;270                 }271             }272         }273     }274 }275 276 /*遍历编号从st到ed之间的所有缓冲轨道,尽可能对其进行优化*/277 void trainDispatch::adjust(int st, int ed) {278     int largest = findLargestTop(st, ed);279     if (largest == -1) {  //若均为空栈,不用调整 280         return;281     }282     while (largest != -1) {283         int leftLargest = findLargestLessThan(largest, st, largest-1);284         while (leftLargest != -1) {285             int temp = stackArray[leftLargest].top();286             stackArray[leftLargest].pop();287             if (stackArray[leftLargest].empty() || stackArray[leftLargest].top() > stackArray[largest].top()) {288                 stackArray[largest].push(temp);289                 cout << "the carrage-" << temp << " move out of stack-" << leftLargest+1290                       << ", then move in the stack-" << largest+1<< "\n";291                 largest = findLargestTop(st, ed);292                 break;293             } else {294                 stackArray[leftLargest].push(temp);295                 leftLargest = findLargestLessThan(leftLargest, st, largest-1);296             }297         }298         if (leftLargest == -1) {299             largest = findLargestLessThan(largest, st, ed);300         }301     }302 }303 304 int main() {305     trainDispatch t;306     t.solution();307     return 0;308 }
View Code

火车车厢重排问题