《算法竞赛入门经典》 例题5-2 木块问题(The Blocks Problem,UVa 101)
原題及翻譯
Many areas of Computer Science use simple, abstract domains for both analytical and empirical studies.
計算機科學的許多領(lǐng)域都使用簡單、抽象的領(lǐng)域進行分析和實證研究。
For example, an early AI study of planning and robotics (STRIPS) used a block world in which a robot arm performed tasks involving the manipulation of blocks.
例如,早期的人工智能規(guī)劃和機器人(strips)研究使用了一個塊世界,在這個世界中,機器人手臂執(zhí)行涉及塊操作的任務(wù)。
In this problem you will model a simple block world under certain rules and constraints.
在這個問題中,您將在特定的規(guī)則和約束下建模一個簡單的塊世界。
Rather than determine how to achieve a specified state, you will “program” a robotic arm to respond to a limited set of commands.
您將“編程”一個機械臂來響應(yīng)有限的一組命令,而不是確定如何實現(xiàn)指定的狀態(tài)。
The problem is to parse a series of commands that instruct a robot arm in how to manipulate blocks that lie on a flat table.
問題是要解析一系列命令,這些命令指示機器人手臂如何操作放在平板上的塊。
Initially there are n blocks on the table (numbered from 0 to n ? 1) with block bi adjacent to block bi+1 for all 0 ≤ i < n ? 1 as shown in the diagram below:
最初,表上有n個塊(編號從0到n?1),所有0≤i<n?1的塊bi與塊bi+1相鄰,如下圖所示:
Initial Blocks World
初始塊世界
The valid commands for the robot arm that manipulates blocks are:
操作塊的機器人臂的有效命令是:
?move a onto b
?將A移到B上
where a and b are block numbers, puts block a onto block b after returning any blocks that are stacked on top of blocks a and b to their initial positions.
如果A和B是塊號,則在將堆疊在塊A和B頂部的任何塊返回到其初始位置后,將塊A放在塊B上。
?move a over b
?將A移到B上
where a and b are block numbers, puts block a onto the top of the stack containing block b, after returning any blocks that are stacked on top of block a to their initial positions.
如果A和B是塊號,則將塊A放在包含塊B的堆棧頂部,然后將堆疊在塊A頂部的任何塊返回到其初始位置。
?pile a onto b
?A樁到B樁
where a and b are block numbers, moves the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto block b.
如果A和B是塊號,則將由A塊和堆放在A塊上方的任何塊組成的一堆塊移動到B塊上。
All blocks on top of block b are moved to their initial positions prior to the pile taking place.
B塊頂部的所有塊在樁發(fā)生之前移動到其初始位置。
The blocks stacked above block a retain their order when moved.
堆疊在A塊上方的塊在移動時保持其順序。
?pile a over b
?A樁超過B樁
where a and b are block numbers, puts the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto the top of the stack containing block b.
如果A和B是塊編號,則將由A塊和A塊以上的任何塊組成的一堆塊放在包含B塊的堆棧頂部。
The blocks stacked above block a retain their original order when moved.
A塊以上的塊移動時保持其原始順序。
?Quit
退出
terminates manipulations in the block world.
終止塊世界中的操作。
Any command in which a = b or in which a and b are in the same stack of blocks is an illegal command.
A=B或A和B在同一組塊中的任何命令都是非法命令。
All illegal commands should be ignored and should have no affect on the configuration of blocks.
應(yīng)忽略所有非法命令,并且不應(yīng)影響塊的配置。
Input
輸入
The input begins with an integer n on a line by itself representing the number of blocks in the block world.
輸入以一行上的整數(shù)n開始,該整數(shù)本身表示塊世界中的塊數(shù)。
You may assume that 0 < n < 25.
你可以假設(shè)0<n<25。
The number of blocks is followed by a sequence of block commands, one command per line.
塊的數(shù)量后面跟著一系列塊命令,每行一個命令。
Your program should process all commands until the quit command is encountered.
在遇到退出命令之前,程序應(yīng)該處理所有命令。
You may assume that all commands will be of the form specified above.
您可以假定所有命令都將采用上面指定的格式。
There will be no syntactically incorrect commands.
在語法上不會有錯誤的命令。
Output
輸出
The output should consist of the final state of the blocks world.
輸出應(yīng)包括塊世界的最終狀態(tài)。
Each original block position numbered i (0 <=i <n where n is the number of blocks) should appear followed immediately by a colon.
每個編號為i的原始塊位置(0 <=i <n,其中n是塊的數(shù)量)應(yīng)緊跟冒號出現(xiàn)。
If there is at least a block on it, the colon must be followed by one space, followed by a list of blocks that appear stacked in that position with each block number separated from other block numbers by a space.
如果上面至少有一個塊,冒號后面必須跟一個空格,后面是一個顯示在該位置的塊列表,每個塊編號與其他塊編號之間用空格分隔。
Don’t put any trailing spaces on a line.
不要在一行上放任何尾隨空格。
There should be one line of output for each block position (i.e., n lines of output where n is the integer on the first line of input).
每個塊位置應(yīng)有一行輸出(即,n行輸出,其中n是輸入第一行的整數(shù))。
Sample Input
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit
Sample Output
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:
思路
1.因為每個木塊堆的高度不確定,所以用vector來保存很合適;而木堆的個數(shù)不超過n,所以用一個數(shù)組來存就可以了。
2.輸入一共有4種指令,但如果完全獨立地處理各指令,代碼就會變得冗長而且易錯,更好的方法是提取出指令之間的共同點,編寫函數(shù)以減少重復代碼。
代碼分析
1.把第p堆高度為h的木塊上方的所有木塊移回原位:
void clear_above (int p,int h) {for(int i=h+1;i<pile[p].size();i++){int b=pile[p][i];pile[b].push_back(b); //把木塊b放回原位}pile[p].resize(h+1); //pile只應(yīng)保留下標0~h的元素 }2.把第p堆高度為h及其上方的木塊整體移動到p2堆的頂部:
void pile_onto(int p,int h,int p2) {for(int i=h;i<pile[p].size();i++){pile[p2].push_back(pile[p][i]);}pile[p].resize(h); }3.找木塊a所在的pile和height,以引用的形式返回調(diào)用者:
void find_block(int a,int& p,int& h) {for(p=0;p<n;p++){for(h=0;h<pile[p].size();h++){if(pile[p][h]==a) return;}} }4.最后用于打印的函數(shù):
void print() {for(int i=0;i<n;i++){printf("%d:",i);for(int j=0;j<pile[i].size();j++){printf(" %d",pile[i][j]);}printf("\n");} }5.主函數(shù),用于讀入、處理數(shù)據(jù)和調(diào)用函數(shù):
int main () {int a,b;cin>>n;//n個木塊string s1,s2;//聲明兩個字符串類型的變量,用于讀入命令for(int i=0;i<n;i++){//將木塊全部放在初始位置上pile[i].push_back(i);}while(cin>>s1>>a>>s2>>b){int pa,pb,ha,hb;find_block(a,pa,ha);find_block(b,pb,hb);//找到兩個木塊所在的位置if(pa==pb) continue;if(s2=="onto") clear_above(pb,hb);if(s1=="move") clear_above(pa,ha);pile_onto(pa,ha,pb);}print();return 0; }完整代碼
#include <cstdio> #include <string> #include <vector> #include <iostream> using namespace std; const int maxn=30; int n; vector <int> pile[maxn]; //每個pile[i]是一個vector void find_block(int a,int& p,int& h) {//找木塊a所在的pile和height,以引用的形式返回調(diào)用者for(p=0;p<n;p++){for(h=0;h<pile[p].size();h++){if(pile[p][h]==a) return;}} } void clear_above (int p,int h) {//把第p堆高度為h的木塊上方的所有木塊移回原位for(int i=h+1;i<pile[p].size();i++){int b=pile[p][i];pile[b].push_back(b); //把木塊b放回原位}pile[p].resize(h+1); //pile只應(yīng)保留下標0~h的元素 } void pile_onto(int p,int h,int p2) {//把第p堆高度為h及其上方的木塊整體移動到p2堆的頂部for(int i=h;i<pile[p].size();i++){pile[p2].push_back(pile[p][i]);}pile[p].resize(h); } void print() {for(int i=0;i<n;i++){printf("%d:",i);for(int j=0;j<pile[i].size();j++){printf(" %d",pile[i][j]);}printf("\n");} } int main () {int a,b;cin>>n;string s1,s2;for(int i=0;i<n;i++){pile[i].push_back(i);}while(cin>>s1>>a>>s2>>b){int pa,pb,ha,hb;find_block(a,pa,ha);find_block(b,pb,hb);if(pa==pb) continue;if(s2=="onto") clear_above(pb,hb);if(s1=="move") clear_above(pa,ha);pile_onto(pa,ha,pb);}print();return 0; }總結(jié)
以上是生活随笔為你收集整理的《算法竞赛入门经典》 例题5-2 木块问题(The Blocks Problem,UVa 101)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《算法竞赛入门经典》 例题5-1 大理石
- 下一篇: 《算法竞赛入门经典》习题3-1 得分(S