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)

 

 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 }
View Code

 感觉应该从这道题学的就是只需要记录i时刻在哪个站就可以获得足够的信息,而没必要存储每个位置,而且记录在哪个站还更容易设计转移状态

 

同样的,UVA437,将的有n种立方体,三条边分别为x,y,z,每种都有无数个。要求叠放时一个立方体的底面长宽严格小于其下方的底面长宽。

这显然是一个DAG图,对于每个立方体,存储它的三种摆放状态即可,但是如果我们直接存储边长,需要max_len *max_len的花销,显然会有不少的浪费。其实我们只需要定义这三种摆放方式,然后存储摆放方式和使用的立方体序号即可。例如按照第几长的边作高区别摆放的状态,这样只需要3*n的花销。

存储下标是一种很有用的方式。因为我们可以通过下标读取数值。这样有时我们可以利用更小的空间来获得更多的信息。还有就是有些要求不能重复的题目,如果你直接存储数值,难以判断是否重复,因为有可能不同的物品有同样的部分特征,这时存储下标有更好的区别效果,输出时按下标访问,也很方便。

posted @ 2017-08-21 14:35  xFANx  阅读(134)  评论(0编辑  收藏  举报