2020安徽省大学生程序设计大赛题解——K 农夫打狼
K 农夫打狼
题解
标签
排序,动态规划
分析
图
K
−
1
本
题
的
一
个
样
例
,
彩
色
十
字
为
起
点
和
终
点
图K-1 \ \ \ \ 本题的一个样例,彩色十字为起点和终点
图K−1 本题的一个样例,彩色十字为起点和终点
想要让全程路径长度最短,有一点是毋庸置疑的,那就是农夫在刚到第 i i i层时,会找到第 i i i层最左 / / /最右边的狼开始,并按照从左向右 / / /从右向左的顺序杀完该层所有的狼,最后到达第 i i i层最右 / / /最左边的狼的位置。所以我们把所有点按 y y y坐标排序,对于 y y y坐标相同的点,求出 x x x坐标最小值和最大值。
图
K
−
2
在
完
成
一
层
后
,
上
楼
并
按
照
左
右
顺
序
走
完
该
楼
层
图K-2 \ \ \ \ 在完成一层后,上楼并按照左右顺序走完该楼层
图K−2 在完成一层后,上楼并按照左右顺序走完该楼层
农夫在杀完第 i i i层狼后,他的终点坐标一定在第 i i i层的最左边的狼处或者在最右边的狼处。这既是第 i i i层的终点,又是第 i + 1 i+1 i+1层的起点。
本来我们希望用dp[i]表示杀完前 i i i层狼所需要的最短路径的,但这样不便处理。基于上述描述,我们可以把动态规划
设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示杀完前 i i i层的狼,并回到 j = 0 j=0 j=0(第 i i i层最左边) / / / j = 1 j=1 j=1(第 i i i层最右边),所需要的最小路程,那么 d p [ n ] [ n ] dp[n][n] dp[n][n]即为所求。
我们再考虑状态转移,这个二维数组的状态转移关系很容易得出,即 d p [ i − 1 ] [ 0 ] 、 d p [ i − 1 ] [ 1 ] dp[i-1][0]、dp[i-1][1] dp[i−1][0]、dp[i−1][1]到 d p [ i ] [ 0 ] 、 d p [ i ] [ 1 ] dp[i][0]、dp[i][1] dp[i][0]、dp[i][1]的状态转移。
具体的状态转移方程如下,至于是如何得出的,再看完程序后自然能够理解。
dp[i][0] = min(dp[i - 1][0] + abs(maxx[i - 1] - minx[i]),
dp[i - 1][1] + abs(maxx[i - 1] - minx[i])) + dis + 1;
dp[i][1] = min(dp[i - 1][0] + abs(minx[i - 1] - maxx[i]),
dp[i - 1][1] + abs(maxx[i - 1] - maxx[i])) + dis + 1;
参考答案(C++)
#include<bits/stdc++.h>
using namespace std;
struct point {
int x, y;
point() {}
point(int x, int y) {
this->x = x;
this->y = y;
}
}p[100005];
bool cmp(point a, point b) {
return a.y == b.y ? a.x < b.x : a.y < b.y;
}
int dp[100005][2];
int minx[100005], maxx[100005];
int m, n, x, y;
int main() {
cin >> n >> m;
minx[0] = maxx[0] = 0;
for (int i = 1; i < n; i++) {
maxx[i] = -1;
minx[i] = 100005;
}
minx[n] = maxx[n] = n;
for (int i = 0; i < m; i++) {
cin >> x >> y;
p[i] = point(x, y);
}
sort(p, p + m, cmp);
for (int i = 0; i < m; i++) {
minx[p[i].y] = min(minx[p[i].y], p[i].x);
maxx[p[i].y] = max(maxx[p[i].y], p[i].x);
}
for (int i = 1; i <= n; i++) {
if (minx[i] == 100005) {
minx[i] = minx[i - 1];
maxx[i] = maxx[i - 1];
}
}
for (int i = 1; i <= n; i++) {
int dis = maxx[i] - minx[i];
dp[i][0] = min(dp[i - 1][0] + abs(maxx[i - 1] - minx[i]),
dp[i - 1][1] + abs(maxx[i - 1] - minx[i])) + dis + 1;
dp[i][1] = min(dp[i - 1][0] + abs(minx[i - 1] - maxx[i]),
dp[i - 1][1] + abs(maxx[i - 1] - maxx[i])) + dis + 1;
}
cout << min(dp[n][0], dp[n][1]) << endl;
return 0;
}