1 条题解
-
2
小蓝与忍者游戏
tag
博弈论,贪心,枚举
题意简述
在一个 的棋盘上,在 处有一个棋子,A 和 B 轮流操作,A可以将棋子向下移动或者放弃操作,B可以向右移动或者放弃操作。同时场上存在障碍物,棋子不能移动到障碍物上或者越界。A的目的是最大化移动次数,B的目的是最小化移动次数。当两人在同一回合均放弃操作时,游戏结束。问A的移动次数。
题解思路
A的目的是最大化移动次数,因此A的移动策略一定是能动则动,这样一定是最优的。因此对于A来说,若不考虑列标的影响,A一定会将棋子移动到本列向下的第一个障碍物前或者是边界处。再来分析B,对于B而言,实际上游戏的结束权力在B手上。因为,B可以控制棋子所在的列数,当B移动到第 列时,A的结果已经是确定的了,可以用
set
容器的二分方法二分当前A
所在的行标直接得到答案。而B最后要最小化棋子移动的次数,那么他一定会在A能移动的最小的一列停下。因此,我们只需要模拟棋子的移动过程(因为每个回合都一定会让棋子向下和向右移动一个单位,除非有障碍物),然后记录每一列A能移动的次数,取最小值即可。
参考代码
void solve() { int n, m, k; cin >> n >> m >> k; vector<set<int>> pos(m + 1); // 记录每一列的障碍物的行标 for(int i = 1; i <= m; i ++) { pos[i].insert(n + 1); // 插入n+1作为每一列的边界 } int ans = 1e9; while(k--) { int x, y; cin >> x >> y; pos[y].insert(x); } int x = 1, y = 1; int last_x = -1; for(int i = 1; i <= n; i ++) { // 如果当前行有障碍物,则移动到障碍物前,答案就是障碍物的坐标-2 // 注意一下,如果列没有发生改变(也就是右边存在障碍物的时候),则答案不变,因为第一次的答案是最大的 if(x != last_x) ans = min(ans, *pos[y].lower_bound(x) - 2); last_x = x; // 模拟移动过程,如果目的地没有障碍物或者越界,则移动 // 注意由于是A先手,因此一定是先移动列(向下),再移动行(向右) if(x + 1 <= n and pos[y].count(x + 1) == 0) x++; if(y + 1 <= m and pos[y + 1].count(x) == 0) y++; } // 最后还有回合结束双方都放弃的操作次数,因此答案要+1 cout << ans + 1 << '\n'; }
信息
- ID
- 225
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 17
- 已通过
- 4
- 上传者