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 }

 

转载于:https://www.cnblogs.com/cxhscst2/p/6636910.html

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值