NOIP2017记录

分享了作者在编程竞赛中遇到的问题及解决思路,包括图论、拓扑排序等算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
D1
T1:找规律?
虽然这好像是小学奥数,但手推了十多分钟也很难有严谨证明,手出了几组数据就直接上结论了……
最后30分钟没事做,用rand()验证了一下算法的正确性 手动滑稽

T2:
题目略长,看了半天才读懂
第一眼看上去是道码农题,为了方便调试写了四五个函数,整整70行代码,写完还剩接近一个半小时
其实就是简单的压栈和字符串处理.

T3:
图论,
讲真,一开始我连暴力都想不到
yy了一会,决定上bfs+priority_queue乱搞
40min左右开始调试,感觉想到了一种更好的做法:

先上拓扑排序判-1,反向用spfa求每个点到终点的最小距离 dis[],
当搜索到一个点时,如果 len > dis[u]+k 直接退出

其实正解也与此类似,把每个点拆成 k 个点,再 spfa ,O(NK) 能过,不过以我的码力短时间内应该实现不了.

但只剩下了50min了,在短时间内写出来的可能性不大,写完暴力,就开始愉快的检查文操了

D2:
听说要考网络流,看了半晚上的dicnic,结果报道出了偏差 .

T1:
暴力模拟建图,赛后有人说可能会TLE

T2:
读完题面后看到 n <= 12 的数据范围,整个人都懵了,为什么我想到的是 prim???
可能我sometimes naive,但能过样例啊!
(贪心过样例/暴力出奇迹)
赛后出题人表示标算的复杂度是 O(n^4),贪心的大概是凉了.

T3:
感觉T3的题面比T2清晰,于是先上T3的暴力了
时间 O((n+m)×q)O((n+m)×q),空间 O(m×n)O(m×n) 的模拟结合n==1时的vector<>,就可以水50分左右,

然后开始想正解:

开n*m的数组(或bitset) 就会MLE,
所以正解应该用到了链表 vector
然后对操作分两种情况讨论?
可以用vector维护最后一列,再开n个vector维护新加入的点
但如果询问原本没出列的点呢?
查询每一行原有的点中有多少个点被删除,然后上二分?
map? bitset? 好像都不行,然后果断回T2写了个prim.

在最后还剩40分钟左右的时候注意到:对于50%的数据,q <= 500 我还能水分!
于是开500*m大小的数组,直接维护最后一列,大概能多水20分吧……

补充:D2T3 亲测 vector 的常数大到……,n==1的20分大概只有10分了

### NOIP 2017 棋盘题目解析 #### 题目背景与描述 在NOIP 2017普及组比赛中,棋盘问题是其中一道具有挑战性的试题。该问题主要考察选手对于深度优先搜索(DFS)及其优化技巧的理解和应用能力[^1]。 #### 考察知识点 此题重点在于深搜算法的应用以及如何通过合理的策略减少不必要的计算量——即所谓的“剪枝”。具体来说: - **深搜回溯**:当遇到无法继续放置新棋子的情况时,应回退至上一步并尝试其他可能性。 - **最优化剪枝**:为了提高效率,在遍历过程中应尽早排除明显不可能成功的路径。 #### 解决方案概述 针对这个问题的一个有效解决方案是采用基于DFS的方法,并结合特定条件下的提前终止机制来进行性能上的改进。以下是实现这一方法的关键要点: - 使用二维数组表示棋盘状态; - 对于每一个可能的位置,判断是否可以安全地放下当前类型的棋子; - 如果当前位置合法,则更新棋盘并将新的位置作为起点递归调用函数处理后续操作; - 当发现某个分支不再满足获胜条件时立即停止探索这条路线,转而测试其它选项; - 记录下所有成功完成布局的方式数量作为最终答案返回。 ```cpp #include <iostream> using namespace std; const int N = 8; int n, m, k; // 定义全局变量n,m,k分别代表行数、列数和需要摆放的皇后数目 bool row[N], col[N], diag1[2*N-1], diag2[2*N-1]; // 行、列、两个方向对角线占用情况标记表 int ans = 0; void dfs(int r){ if(r == n){ // 找到了一种可行解法 ++ans; return ; } for (int c=0;c<m;++c){ if (!row[r] && !col[c] && !diag1[r+c] && !diag2[r-c+n-1]){ // 判断能否在此处放一个棋子 row[r]=true,col[c]=true,diag1[r+c]=true,diag2[r-c+n-1]=true; // 更新各维度的状态 dfs(r+1); // 继续向下一层递归 row[r]=false,col[c]=false,diag1[r+c]=false,diag2[r-c+n-1]=false; // 回溯恢复现场 } } } int main(){ cin >> n >> m >> k; dfs(0); cout << ans; } ``` 上述代码片段展示了利用DFS解决N皇后的经典框架,虽然不是完全适用于原版棋盘问题的具体细节,但是体现了相似的核心逻辑和技术手段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值