1. 程式人生 > 實用技巧 >試題 演算法訓練 Lift and Throw

試題 演算法訓練 Lift and Throw

資源限制 時間限制:3.0s 記憶體限制:256.0MB 問題描述   給定一條標有整點(1, 2, 3, ...)的射線. 定義兩個點之間的距離為其下標之差的絕對值.
  Laharl, Etna, Flonne一開始在這條射線上不同的三個點, 他們希望其中某個人能夠到達下標最大的點.
  每個角色只能進行下面的3種操作, 且每種操作不能每人不能進行超過一次.
  1.移動一定的距離
  2.把另一個角色高舉過頭
  3.將舉在頭上的角色扔出一段距離
  每個角色有一個movement range引數, 他們只能移動到沒有人的位置, 並且起點和終點的距離不超過movement range.
  如果角色A和另一個角色B距離為1, 並且角色B沒有被別的角色舉起, 那麼A就能舉起B. 同時, B會移動到A的位置,B原來所佔的位置變為沒有人的位置. 被舉起的角色不能進行任何操作, 舉起別人的角色不能移動.同時, 每個角色還有一個throwing range引數, 即他能把舉起的角色扔出的最遠的距離. 注意, 一個角色只能被扔到沒有別的角色佔據的位置. 我們認為一個角色舉起另一個同樣舉起一個角色的角色是允許的. 這種情況下會出現3個人在同一個位置的情況. 根據前面的描述, 這種情況下上面的兩個角色不能進行任何操作, 而最下面的角色可以同時扔出上面的兩個角色. 你的任務是計算這些角色能夠到達的位置的最大下標, 即最大的數字x, 使得存在一個角色能夠到達x. 輸入格式
  輸入共三行, 分別為Laharl, Etna, Floone的資訊.
  每一行有且僅有3個整數, 描述對應角色的初始位置, movement range, throwing range.
  資料保證3個角色的初始位置兩兩不相同且所有的數字都在1到10之間. 輸出格式   僅有1個整數, 即Laharl, Etna, Flonne之一能到達的最大距離. 樣例輸入 9 3 3
4 3 1
2 3 3 樣例輸出 15 樣例說明   一開始Laharl在位置9, Etna在位置4, Flonne在位置2.
  首先, Laharl移動到6.
  然後Flonne移動到位置5並且舉起Etna.
  Laharl舉起Flonne將其扔到位置9.
  Flonne把Etna扔到位置12.
  Etna移動到位置15. 這題初看挺複雜,連要搜尋什麼都不知道,於是就百度了一下,發現切入點是 每個人可以有3次操作,那麼一共就是9次操作,我們要深搜的就是這9次操作,其他要做的就是剪枝。 感謝這位博主,寫得很詳細,一點就通.
要注意的有以下幾點: 1. 從資料規模可知,最大距離小於50,那麼座標軸的陣列大小開50就足夠了; 2. 9次操作的第一步應當是移動或舉起,而不是丟擲; 3. 若當前是最後一步操作,那麼直接移動至可移動的最大距離 或 丟擲至可丟擲的最大距離; 4. 已移動過、正舉著人、正被舉著的人不能移動;已舉起過、正舉著人、正被舉起的人不能舉起別人;未舉著人、正被舉起的人不能進行丟擲操作; 5. 移動和丟擲的目標位置只需考慮兩種情況:其他人旁邊的位置、可移動/可丟擲的最遠的位置; 6. 若當前操作是移動或丟擲,若當前執行操作的人後面有人,那麼從此人(座標軸最左邊的人)右邊第一個位置開始遍歷;若後面無人,那麼從自己右邊第一個位置開始遍歷; 7. 目標位置必須確保 還在座標軸上(即下標>0)且 目標位置無人;
程式碼有點長,不過其實大部分都是更新執行操作的人的狀態以及回溯,著重要注意和理解的是剪枝,也就是查詢目標和一些判斷的條件.
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <algorithm>
  8 #define INF 0x3f3f3f3f
  9 #define zero 1e-7
 10 
 11 using namespace std;
 12 typedef long long ll;
 13 const ll mod=50000;
 14 const ll max_n=2e5+7;
 15 
 16 struct node {//0表示否,1表示是,-1表示沒舉著任何人 
 17     int pos;//當前所在位置
 18     int maxMove;//可移動的最大距離 
 19     int maxThrow; //可扔出的最大距離 
 20     bool beup;//是否被舉著 
 21     int upwho;//是否舉著,舉著誰 
 22     bool hasmove;//是否曾移動過 
 23     bool hasup;//是否曾舉過(扔過) 
 24 }p[3];//三個人 
 25 
 26 int maxd=0;
 27 bool axis[50]={0};//標記數軸上是否有人,0表示無
 28 bool ops[10]={0};//9個操作全排列 
 29 
 30 void dfs(int k, int step) {
 31     int n=k/3;//當前執行操作的人 
 32     int m=k%3;//當前執行的操作
 33     if(!m) {//移動 
 34         if(p[n].beup || p[n].hasmove || p[n].upwho!=-1) return;//被舉著、移動過、舉著人的人不能移動 
 35         int l=1; 
 36         if(step==9) l=p[n].maxMove;//若當前是最後一步操作,則直接移動最大距離即可 
 37         else {
 38             for(int i=1; i<p[n].pos; i++) {
 39                 if(axis[p[i].pos]) {//找到座標軸上第一個人的位置 
 40                     l=-(p[n].pos-i-1);
 41                     break;
 42                 }
 43             }
 44             l=max(l, -p[n].maxMove);//移動距離不能超過maxMove 
 45         } 
 46         for(int i=l; i<=p[n].maxMove; i++) {
 47             if(axis[p[n].pos+i-1] || axis[p[n].pos+i+1] || i==p[n].maxMove) {//目標位置應是其他人的旁邊的位置或者能移動的最大距離
 48                 if(p[n].pos+i>0 && !axis[p[n].pos+i]) {//確保在座標軸範圍內 且 目標位置無人 
 49                     if(!i) continue;//目標位置不能是自己當前所在位置
 50                     //以下,修改移動後需要更新的值
 51                     axis[p[n].pos]=false;
 52                     p[n].pos+=i;
 53                     axis[p[n].pos]=true;
 54                     p[n].hasmove=true;
 55                     maxd=max(p[n].pos, maxd);
 56                     
 57                     //繼續下一步搜尋
 58                     for(int j=0; j<9; j++) {
 59                         if(!ops[j]) {
 60                             ops[j]=true;
 61                             dfs(j, step+1);
 62                             ops[j]=false;
 63                         }
 64                     }
 65                     //回溯 
 66                     p[n].hasmove=false;
 67                     axis[p[n].pos]=false;
 68                     p[n].pos-=i;
 69                     axis[p[n].pos]=true;
 70                 }    
 71             }
 72         }
 73     }
 74     if(m==1) {//舉起 
 75         if(p[n].upwho!=-1 || p[n].beup || p[n].hasup) return;//未舉著人、被舉著、舉過人的人不能舉起別人
 76         for(int i=0; i<3; i++) {//列舉每個人的位置 
 77             if(abs(p[i].pos-p[n].pos)==1) {//如果剛好有人在這個人旁邊
 78                 if(p[i].beup) continue;//i不能重複被舉起 
 79                 
 80                 p[n].hasup=true;
 81                 p[n].upwho=i;
 82                 p[i].beup=true;
 83                 int temp=p[i].pos;//記錄i的位置,以便回溯
 84                 axis[p[i].pos]=false;
 85                 p[i].pos=p[n].pos;
 86                 if(p[i].upwho!=-1) //若i舉著人 
 87                     p[p[i].upwho].pos=p[i].pos; 
 88                 
 89                 //繼續下一步搜尋
 90                 for(int j=0; j<9; j++) {
 91                     if(!ops[j]) { 
 92                         ops[j]=true;
 93                         dfs(j, step+1);
 94                         ops[j]=false;
 95                     }
 96                 }
 97                 //回溯
 98                 p[n].hasup=false;
 99                 p[n].upwho=-1;
100                 p[i].beup=false;
101                 p[i].pos=temp;
102                 axis[p[i].pos]=true;
103                 if(p[i].upwho!=-1) 
104                     p[p[i].upwho].pos=p[i].pos; 
105             }
106         }
107     } 
108     if(m==2) {//丟擲 
109         if(p[n].upwho==-1 || p[n].beup) return;//若沒有舉起別人或正被舉起,則不可丟擲
110         int l=1;
111         if(step==9) l=p[n].maxThrow;//若當前為最後一步操作,則直接丟擲到最遠距離 
112         else {
113             for(int i=1; i<p[n].pos; i++) {
114                 if(axis[i]) {
115                     l=-(p[n].pos-i-1);
116                     break;
117                 }
118             }
119             l=max(l, -p[n].maxThrow);//扔出距離不能超過maxThrow 
120         } 
121         for(int i=l; i<=p[n].maxThrow; i++) {
122             if(p[n].pos+i>0 && !axis[p[n].pos+i]) {//確保目標位置還在座標軸範圍內 且 目標位置無人 
123                 if(axis[p[n].pos+i-1] || axis[p[n].pos+i+1] || i==p[n].maxThrow) {//目標位置應是其他人旁邊或可扔出的最大距離 
124                 
125                     int temp=p[n].upwho;//記錄舉著誰以便回溯 
126                     p[temp].pos+=i;
127                     p[temp].beup=false;
128                     p[n].upwho=-1;
129                     p[n].hasup=true;
130                     axis[p[temp].pos]=true;
131                     maxd=max(maxd, p[temp].pos);
132                     if(p[temp].upwho!=-1) 
133                         p[p[temp].upwho].pos=p[temp].pos;
134                     
135                     //繼續下一步搜尋
136                     for(int j=0; j<9; j++) {
137                         if(!ops[j]) {
138                             ops[j]=true;
139                             dfs(j, step+1);
140                             ops[j]=false;
141                         }
142                     } 
143                     //回溯
144                     axis[p[temp].pos]=false;
145                     p[temp].pos=p[n].pos;
146                     p[temp].beup=true;
147                     p[n].upwho=temp;
148                     if(p[temp].upwho!=-1)
149                         p[p[temp].upwho].pos=p[temp].pos; 
150                 }
151             }
152         }
153     }
154 } 
155 
156 int main() {
157     for(int i=0; i<3; i++) {
158         cin>>p[i].pos>>p[i].maxMove>>p[i].maxThrow;
159         p[i].beup=false;
160         p[i].upwho=-1;
161         p[i].hasmove=false;
162         p[i].hasup=false;
163         axis[p[i].pos]=true;
164     }
165     
166     for(int i=0; i<9; i++) {
167         if(i%3!=2) {//第一步應是移動或舉起 
168             ops[i]=true;
169             dfs(i, 1);
170             ops[i]=false;//回溯 
171         }
172     }
173     printf("%d\n", maxd);
174     return 0;
175 }
176 
177 /*
178 9 3 3
179 4 3 1
180 2 3 3
181 
182 15
183 */