NOIP 2014 Senior 3
来源:互联网 发布:阿里云cdn价格下调25 编辑:程序博客网 时间:2024/06/15 14:52
思路1
看到50分都是搜索的范围,于是我就爆搜了。恭喜,我又写对了(不容易啊,所以要多检查,增加静态查错能力),所以还是贴一个代码吧。
const int maxn = 10005;int n, m, k;INT X[maxn];INT Y[maxn];struct pipe{ INT P; INT L; INT H; bool operator< (const pipe& b) const { return P < b.P; }} pipes[maxn];INT minClick = 0x7fffffff;INT maxThrough;bool bWin;INT pipeIndex;INT click;void dfs(int h, int x = 1){ if (click > minClick) return; if (x == n + 1) { minClick = std::min(minClick, click); bWin = true; return; } bool onPipe = false; INT maxH = m; INT minH = 0; if (pipeIndex < k && pipes[pipeIndex].P == x) { onPipe = true; maxH = pipes[pipeIndex].H; minH = pipes[pipeIndex].L; pipeIndex++; } if (h - Y[x] > minH && h - Y[x] < maxH) { if (onPipe) maxThrough = std::max(pipeIndex, maxThrough); dfs(h - Y[x], x + 1); } for (int i = X[x], j = 1; h + i - X[x] < m; i += X[x], j++) { int next = std::min(m, h + i); if (next > minH && (!onPipe || next < maxH)) { click += j; if (onPipe) maxThrough = std::max(pipeIndex, maxThrough); dfs(next, x + 1); click -= j; } } if (onPipe) pipeIndex--;}void run(){ n = readIn(); m = readIn(); k = readIn(); for (int i = 1; i <= n; i++) { X[i] = readIn(); Y[i] = readIn(); } for (int i = 0; i < k; i++) { pipes[i].P = readIn(); pipes[i].L = readIn(); pipes[i].H = readIn(); } std::sort(pipes, pipes + k); for (int i = m; i >= 1; i--) dfs(i); if (bWin) cout << 1 << endl << minClick << endl; else cout << 0 << endl << maxThrough << endl;}
我本来还以为这道题是通过神级剪枝过的,但是我就想到一个最优化剪枝,其它的。。。
思路2 DP
说好的第一天第三题考考搜索呢(其实没有人说)!谈到搜索,我们自然会想到DP ——DP的问题引入不都是从搜索会超时开始的吗。这道题也可以DP,状态也很好描述,就是一个点的坐标。所以我们设f[x][y]
代表到坐标(x, y)时最小的点击次数。应该还是很好想到一个状态转移方程,就是根据x - 1时的坐标和点击的次数k来计算横坐标为x时对应的位置。但很明显,由于引入了k,时间复杂度将变为
其实,这道题有点像背包dp:向下是01背包,向上是完全背包,只不过有一些特别的限制。为了解决刚刚k那个问题,我们可以参考(没用滚动数组的)完全背包的做法:既可以在未选择物品i的状态中选,也可以在选择了物品i的状态中选。换在这道题上,就是既可以通过在横坐标为x - 1时点击一次到横坐标为x的对应位置,也可以在横坐标为x的地方继续点一次。
所以怎么处理管子呢?我们不如先转移状态,然后再将限制加上。最后,一定要记住先更新向上的,再更新向下的,因为根据刚刚的思路会向下向上同时进行,不符合题意。
当然,再来个滚动数组就好了。
参考代码(渣)
#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <string>#include <stack>#include <queue>#include <deque>#include <map>#include <set>using std::cin;using std::cout;using std::endl;typedef int INT;inline INT readIn(){ bool minus = false; INT a = 0; char ch = getchar(); while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { a *= 10; a += ch; a -= '0'; ch = getchar(); } if (minus) a = -a; return a;}const int maxn = 10005;const int maxm = 1005;int n, m, k;INT X[maxn];INT Y[maxn];INT L[maxn];INT H[maxn];int nPipe[maxn];INT f[2][maxm];void run(){ n = readIn(); m = readIn(); k = readIn(); H[0] = m + 1; for (int i = 1; i <= n; i++) { X[i] = readIn(); Y[i] = readIn(); L[i] = 0; H[i] = m + 1; } for (int i = 0; i < k; i++) { INT P = readIn(); nPipe[P] = true; L[P] = readIn(); H[P] = readIn(); } for (int i = 1; i <= n; i++) //走到nPipe[i]时过的管子数 { if (nPipe[i]) nPipe[i] = nPipe[i - 1] + 1; else nPipe[i] = nPipe[i - 1]; } const INT INF = 0x3f3f3f3f; //往往极大值策略比-1策略还要有效 INT farthest = 0; for (int i = 1; i <= n; i++) { int cnt = i & 1; int last = (i + 1) & 1; memset(f[cnt], 0x3f, sizeof(f[cnt])); for (int j = X[i]; j <= m; j++) //不碰顶的 { f[cnt][j] = std::min(f[cnt][j], f[last][j - X[i]] + 1); f[cnt][j] = std::min(f[cnt][j], f[cnt][j - X[i]] + 1); if (j > L[i] && j < H[i] && f[cnt][j] != INF) farthest = i; //若这个地方可以到,就更新走到的最远的地方 } for (int j = m - X[i]; j <= m; j++) //碰顶的 { f[cnt][m] = std::min(f[cnt][m], f[last][j] + 1); f[cnt][m] = std::min(f[cnt][m], f[cnt][j] + 1); if (j > L[i] && j < H[i] && f[cnt][j] != INF) farthest = i; } for (int j = L[i] + 1; j < H[i]; j++) //下落 { if (j + Y[i] <= m) { f[cnt][j] = std::min(f[cnt][j], f[last][j + Y[i]]); if (j > L[i] && j < H[i] && f[cnt][j] != INF) farthest = i; } } //处理不能到的地方 for (int j = 0; j <= L[i]; j++) { f[cnt][j] = INF; } for (int j = H[i]; j <= m; j++) { f[cnt][j] = INF; } } INT ans = INF; for (int i = 1; i <= m; i++) { if (f[n & 1][i] < ans) { ans = f[n & 1][i]; } } if (ans == INF) { cout << 0 << endl << nPipe[farthest] << endl; } else { cout << 1 << endl << ans << endl; }}int main(){ run(); return 0;}
DP Orz
阅读全文
0 0
- NOIP 2014 Senior 3
- NOIP 2014 Senior 2
- NOIP 2014 Senior 5
- NOIP 2014 Senior 6
- NOIP 2009 Senior 3
- NOIP 2011 Senior 3
- NOIP 2012 Senior 3
- NOIP 2015 Senior 3
- NOIP 2013 Senior 3
- NOIP 2016 Senior 3
- NOIP 2003 Senior 3
- NOIP 2005 Senior 3
- NOIP 2017 Senior 3
- NOIP 2009 Senior 1
- NOIP 2009 Senior 4
- NOIP 2011 Senior 2
- NOIP 2011 Senior 4
- NOIP 2011 Senior 5
- MATLAB中自带的核密度估计函数
- java页面后台数据交互(1)
- kNN与kMeans聚类算法的区别
- 1792_迷宫
- hibernate所需jar包
- NOIP 2014 Senior 3
- a 标签中调用js的几种方法
- 常见 HTTP 响应状态码
- 【简记】Java Web 内幕——Servlet介绍,编程
- Java死锁的简单例子
- 【Shell】命令代换
- 2017.7.15 C组总结
- Windows下 搭建WEEX遇到的坑!!
- 156_LETTERS