NOIP 2014飞扬的小鸟(DP优化)

题目链接  飞扬的小鸟

考场的70分暴力(实际只有50分因为数组开小了……)

考场代码(数组大小已修改)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <functional>
 6 
 7 using namespace std;
 8 
 9 #define rep(i, a, b)    for (int i(a); i <= (b); ++i)
10 #define dec(i, a, b)    for (int i(a); i >= (b); --i)
11 #define LL        long long
12 #define fi        first
13 #define se        second
14 
15 
16 const int INF = 1    <<    30;
17 const int N = 10000    +    10;
18 const int M = 1000    +    10;
19 
20 int dp[M][N], x[N], y[N], u[N], d[N];
21 int n, m, q, ans, xn, ln, rn, _max, pos;
22 bool c[N];
23 
24 int main(){
25 
26     scanf("%d %d %d ", &n, &m, &q);
27     rep(i, 0, n - 1) scanf("%d %d ", x + i, y + i);
28     rep(i, 0, n) u[i] = m, d[i] = 1;
29     memset(c, false, sizeof c);
30     rep(i, 1, q){ 
31         scanf("%d %d %d ", &xn, &ln, &rn); 
32         c[xn] = true;
33         u[xn] = rn - 1;  
34         d[xn] = ln + 1;
35     }
36     //rep(i, 0, n) printf("%d %d\n", d[i], u[i]);
37     memset(dp, 0xff70, sizeof dp);_max = dp[1][1];
38     rep(i, 0, m) dp[0][i] = 0;
39     rep(i, 0, n - 1){
40         rep(j, d[i], u[i]){
41             if (dp[i][j] >= _max) continue;
42             int k = j - y[i];
43             if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j]);
44             k = j;int num = 0;
45             while (true){
46                 k += x[i]; ++num;
47                 if (k > m) k = m;
48                 if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j] + num);
49                 if (k == m) break;
50             }
51         }
52     }
53     
54     ans = _max;
55     rep(i, 1, m) ans = min(ans, dp[n][i]);
56     if (ans < _max){
57         printf("%d\n%d\n", 1, ans);return 0;
58     }
59     
60     bool flag = false;
61     ans = 0;
62     dec(i, n, 0) {rep(j, 0, m)  if (dp[i][j] < _max) { pos = i - 1;flag = true; break;} if (flag) break;}
63     dec(i, pos, 0) if (c[i]) ++ans;
64     printf("%d\n%d\n", 0, ans);
65     
66     
67     
68     return 0;
69 }

 

然后回过来想正解。

其实我们把很多时间都浪费在这里了:

1     while (true){
2         k += x[i]; ++num;
3         if (k > m) k = m;
4         if (k >= 0 && k <= m) dp[i + 1][k] = min(dp[i + 1][k], dp[i][j] + num);
5         if (k == m) break;
6     }

 

其实这一步可以转过来直接利用完全背包的性质优化一下。转移只要O(1)就可以了。

这道题细节还是很多的,比较容易写挂。

正解:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define rep(i, a, b)    for (int i(a); i <= (b); ++i)
 6 #define dec(i, a, b)    for (int i(a); i >= (b); --i)
 7 
 8 const int INF = 1    <<    29;
 9 const int N = 10000    +    10;
10 const int M = 1000    +    10;
11 
12 int dp[N][M], x[N], y[N], u[N], d[N];
13 int n, m, q, ans, xn, ln, rn, _max, pos;
14 bool c[N];
15 
16 int main(){
17 
18     scanf("%d %d %d ", &n, &m, &q);
19     u[n] = m + 1; d[n] = 0;
20     rep(i, 0, n - 1) scanf("%d %d ", x + i, y + i), u[i] = m + 1, d[i] = 0;
21 
22 
23     rep(i, 1, q){ 
24         scanf("%d %d %d ", &xn, &ln, &rn); 
25         u[xn] = rn;  
26         d[xn] = ln;
27     }
28 
29     rep(i, 0, n + 2) rep(j, 0, m + 2) dp[i][j] = INF;
30 
31     rep(i, 1, m) dp[0][i] = 0;
32     rep(i, 1, n){
33         rep(j, x[i - 1], m){
34             dp[i][j] = min(dp[i][j], dp[i - 1][j - x[i - 1]] + 1);
35             dp[i][j] = min(dp[i][j], dp[i][j - x[i - 1]] + 1);
36         }
37 
38         rep(j, m - x[i - 1], m){
39             dp[i][m] = min(dp[i][m], dp[i - 1][j] + 1);
40             dp[i][m] = min(dp[i][m], dp[i][j] + 1);
41         }
42 
43         rep(j, d[i] + 1, u[i] - 1){
44             if (j + y[i - 1] <= m) dp[i][j] = min(dp[i][j], dp[i - 1][j + y[i - 1]]);
45         }
46 
47         rep(j, 1, d[i]) dp[i][j] = INF;
48         rep(j, u[i], m) dp[i][j] = INF;
49     }
50 
51     ans = INF;
52     rep(i, 1, m) ans = min(ans, dp[n][i]);
53     if (ans != INF) return 0, printf("%d\n%d\n", 1, ans);
54     int t = q;
55     dec(i, n, 1){
56         rep(j, 1, m) ans = min(ans, dp[i][j]);
57         if (ans != INF) break;
58         if (u[i] != m + 1) --t;
59     }
60 
61     printf("%d\n%d\n", 0, t);    
62     return 0;
63 }

 

posted @ 2017-03-28 21:12  cxhscst2  阅读(285)  评论(0编辑  收藏  举报