今天进行了一次测试,以下是对本次比赛的总结:
T1
题目:
有一个 n×m 的棋盘,棋盘上的每个格子都放着一枚黑棋或白棋。
你可以改变任意格子的棋子颜色(黑变白或白变黑)。现在你需要用最少的改变次数,使得最终棋盘满足:
- 任意两枚相邻棋子(上下左右相邻)的颜色都不相同。
(1≤n,m≤2×10^3)
思路:
可以暴力使用dfs。看似数据范围会超,但可以发现当它左面或上面格子确定好的时候,就只有一种选择了。所以实际上只有左上角是黑色和左上角是白色两种情况。
当然,我在这里使用的是将两种情况都在输入的时候统计下来,最后直接找最小。
T2
题目:
你正在玩一个闯关游戏。角色初始有 X 点血量,每经过一个关卡,血量会发生变化(可能增加也可能减少)。
已知当角色的血量小于等于 0 时会立即死亡。现在你需要计算:初始血量 X 最少是多少,才能保证顺利通过所有关卡
思路:
假设开始血量为0,实时统计每一刻的血量值并统计最小值,最后用1-min即可,当然不要忘了开始时的血量(也就是ans最小为1)。
T3
题目:
每户人家都藏有一些金币,一个小偷正准备偷金币,但是你知道的,如果偷相邻的两家很容易被发现,因此小偷决定偷不相邻人家的金币。
现在已知每户人家各有多少金币,请你计算能偷到的最多的金币数量。
思路:
dp。统计到第i户人家后偷或不偷的最大金币数,如果不偷就从偷或不偷前一户人家中找最大值,偷的话就要从不偷前一户人家和偷前前户人家中找最大。最后找到最后一户人家偷或不偷的最大值即可。
T4
题目:
给定一个长度为 n 的整数序列 a1,a2,...,an。
你可以把这些数字分成两堆(每个数必须且只能属于其中一堆),设两堆数字的和分别为 X 和 Y。
你需要输出 X×Y 的最大值。
思路:
首先要清楚X和Y的取值。最好是最接近序列的总和的一半。假设序列的总和的一半为x,那么就可以知道:
所以是最值的。那么只需要使用01背包的变形即可。例:
dp[j]=dp[j]|dp[j-a[i]];
然后找最接近一半的,最后乘即可。
T5
题目:
还记得数字金字塔问题吗?
你需要从塔尖(第 1 行第 1 列)走到最后一排。假设你当前在第 i 行第 j 列,那么下一步只能走到:
- 第 i+1 行第 j 列
- 第 i+1 行第 j+1 列
每走到一个位置,你都会获得该位置上的数字。
但是你现在拥有了魔法手套:它可以把某一个位置 的数字变为原来的 2 倍 。
很遗憾,这个手套最多只能使用 k 次,也就是说你最多只能对路径上的 k 个位置使用"翻倍"。
现在你需要计算拥有了魔法手套后你能获得的最大数字和。
思路:
之前有一道金字塔的题目,没有这个k,就是这么解:
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j]);
那有了k又该怎么办呢?把k放到dp中就行啦。k可以通过前面原封不动移过来,也可以从前面的k-1移过来再双倍加上去。例:
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-1][k])+a[i][j];
if(k)dp[i][j][k]=max(max(dp[i-1][j][k-1],dp[i-1][j-1][k-1])+2*a[i][j],dp[i][j][k]);
T6
题目:
你想去环游世界。现在已知从每个城市到另一个城市的路程(有向距离,可能不对称)。
你希望从 1 号城市 出发,找到一条最短的路线,使得:
- 每个城市都恰好经过一次;
- 最后回到 1 号城市。
你需要输出最短路程的长度。
思路:
这道题被我用暴力dfs骗过去了(^_^) 但正确的做法是用状压DP(记忆化搜索)。以记忆化搜索举例(因为简单还能剪枝):
v数组表示此时走过去的城市(用2进制),最后找最小即可。
如果大家有其他想法的,可以补充。