UVA - 1025
题意:在一维的维度上,有一个间谍要从第1站到第n站。已知有从第1站到第n站的车与第n站开向第1站的车。间谍乘车到一个站时可以下车,若此时有车经过该站,他可以立即乘上该车。求保证间谍在T时刻可以到达第n站的前提下,不在车上(即在车站上等待)的最短时间。
输入:多组数据
第一行为n,第二行为T,第三行n-1个整数t1~tn-1(1<=t<=70),表示从ti到ti+1耗时
第四行 M1表示从第1站到第n站的车的数量
第五行 发车时间
第六行 M1表示从第n站到第1站的车的数量
第七行 发车时间
输出:不能到达输出impossible,否则输出最短时间
题解:在确定了车的方向与发车时间之后,我们知道最后的答案只与当前时间与所处的位置有关。由于我们只能在车站换乘,所以其实我们只需要考虑时间与当前处在哪个站。那么我们定义dp[i][j]表示时刻i,间谍处于j站,需要的最少等待时间。由于我们确定了T时刻处于第n站,那么我们逆推回来,最终得到的dp[0][1]即是答案。
对于dp[i][j],间谍可以下车等待,或搭乘向右的车,或搭乘向左的车。对于这个,我们有一个数组来预处理出i时刻是否有车经过j站即可。
总的复杂度时O(NT)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define INF 0x3f3f3f3f 6 #define MOD 1000000007 7 using namespace std; 8 typedef long long LL; 9 10 const int maxn = 55; 11 const int maxt = 255; 12 int t[maxn]; 13 int dp[maxt][maxn]; 14 bool has_train[maxt][maxn][2]; 15 int N, T; 16 int Case; 17 18 void solve() { 19 for (int i = 1; i <= N - 1; i++) dp[T][i] = INF; 20 dp[T][N] = 0; 21 for (int i = T - 1; i >= 0; i--) { 22 for (int j = 1; j <= N; j++) { 23 dp[i][j] = dp[i + 1][j] + 1; 24 if (j < N && has_train[i][j][0] && i + t[j] <= T) {//搭乘向n的 25 dp[i][j] = min(dp[i][j], dp[i + t[j]][j + 1]); 26 } 27 if (j > 1 && has_train[i][j][1] && i + t[j - 1] <= T) {//搭乘向1的 28 dp[i][j] = min(dp[i][j], dp[i + t[j - 1]][j - 1]); 29 } 30 } 31 } 32 printf("Case Number %d: ", ++Case); 33 if (dp[0][1] >= INF) printf("impossible\n"); 34 else printf("%d\n", dp[0][1]); 35 } 36 37 int main(int argc, const char * argv[]) { 38 while (scanf("%d", &N), N) { 39 memset(has_train, 0, sizeof(has_train)); 40 scanf("%d", &T); 41 for (int i = 1; i < N; i++) scanf("%d", &t[i]); 42 int to_right; scanf("%d", &to_right); 43 for (int i = 1; i <= to_right; i++) { 44 int time; scanf("%d", &time); 45 int s = 1; 46 while (time <= T && s < N) { 47 has_train[time][s][0] = 1; 48 time += t[s]; 49 s++; 50 } 51 } 52 int to_left; scanf("%d", &to_left); 53 for (int i = 1; i <= to_left; i++) { 54 int time; scanf("%d", &time); 55 int s = N - 1; 56 while (time <= T && s >= 1) { 57 has_train[time][s + 1][1] = 1; 58 time += t[s]; 59 s--; 60 } 61 } 62 solve(); 63 } 64 return 0; 65 }
感觉应该从这道题学的就是只需要记录i时刻在哪个站就可以获得足够的信息,而没必要存储每个位置,而且记录在哪个站还更容易设计转移状态
同样的,UVA437,将的有n种立方体,三条边分别为x,y,z,每种都有无数个。要求叠放时一个立方体的底面长宽严格小于其下方的底面长宽。
这显然是一个DAG图,对于每个立方体,存储它的三种摆放状态即可,但是如果我们直接存储边长,需要max_len *max_len的花销,显然会有不少的浪费。其实我们只需要定义这三种摆放方式,然后存储摆放方式和使用的立方体序号即可。例如按照第几长的边作高区别摆放的状态,这样只需要3*n的花销。
存储下标是一种很有用的方式。因为我们可以通过下标读取数值。这样有时我们可以利用更小的空间来获得更多的信息。还有就是有些要求不能重复的题目,如果你直接存储数值,难以判断是否重复,因为有可能不同的物品有同样的部分特征,这时存储下标有更好的区别效果,输出时按下标访问,也很方便。