你的粪坑v2
你的粪坑v2
题目描述
一听说这是一场正经比赛,都没人用昵称了?好吧,那就用“你”吧,请自行代入聚聚名字!
这是一道充满味道的题目。
今天举办程序设计比赛,2点30分开始,然而你睡到了2点25分,紧张的你将头发梳成大人模样,敷上一层最贵的面膜,穿着滑板鞋,以飞一般的速度奔向计算机学院准备参加程序设计竞赛!冠军是你的!
然而路上稍不留神,你不小心掉进了一个大粪坑,大粪坑是一个N*N的方格矩阵,每个方格存在着X坨粪,一开始你处在A11的粪坑位,你可以选择向下移动或者向右移动,目标是逃离大粪坑到达ANN。
此外!!敲重点!!每经过一个粪坑,你会触及粪量X(粗俗的说法叫做吃屎),而且每更改一次方向,传说中的粪皇会向你丢粪!!
粪皇是个学过二进制的优雅美男子,所以他丢粪也是相当的儒雅随和。第一次他会向你丢1坨,第二次他会向你丢2坨哦,第三次他会向你丢4坨哦!第四次他会向你丢8坨哦!第五次他会向你丢16坨哦!....,第N次他会向你丢2N-1坨哦!嘤嘤嘤~~~~~~~
机智的你绝不会向粪皇低头!所以你拿起手中的笔记本,打开Codeblocks,写下#include<bits/stdc++.h>,开始计算如何掉最少的发,吃最少的屎,冲出粪坑,到达计院,拿下冠军!
输入
第一行是一个整数T,代表测试数据个数。
对每个测试数据第一行是一个整数N,代表粪坑大小为N*N (1 ≤ N ≤ 100) 。
接下来N行每行N个整数,代表粪坑矩阵A中每个粪坑位的粪量(1 ≤ Aij ≤ 100)。
输出
最少吃屎量
样例输入
1
3
1 4 6
1 1 3
6 1 1
样例输出
10
提示
动态规划
1.本题比常规搜索/DP题多了层套路:更改方向的代价
2.由于n和mp[][]都小于100100,极限数据为:100行100列全为100的矩阵,此时代价为100×199 +
1 < 20000 < 2 () ,因此,这题顶多更改15次方向。
3.通过2很好想到用动态规划来做。用dp[x][y][pos][k]表示到达点 (x,y)时通过pos方向(pos==0代
表从左,pos==1代表从上)转移过来的,当前已经进行了k次方向变化。
4.递推方程如下:
1) 表示从左边状态递推到点(i,j),当左边是从左边(0)继承,则无需付出代价;当左边是从上方(1)
继承,则需要付出改变方向的代价,注意此时左边的状态是k−1的状态。递推方程为:
𝑑𝑝[𝑖][𝑗][0][𝑘] = min(𝑑𝑝[𝑖][𝑗][0][𝑘],min(𝑑𝑝[𝑖][𝑗 − 1][0][𝑘],𝑑𝑝[𝑖][𝑗 − 1][1][𝑘 − 1] + 2 89( )
2)同理,若是从上方递归到点(i,j),递推方程为:
𝑑𝑝[𝑖][𝑗][1][𝑘] = min(𝑑𝑝[𝑖][𝑗][1][𝑘],min(𝑑𝑝[𝑖 − 1][𝑗][1][𝑘],𝑑𝑝[𝑖 − 1][𝑗][0][𝑘 − 1] + 2 89( )
标程: https://paste.ubuntu.com/p/HQbW7w6FFN/
#include <bits/stdc++.h> #define min3(x, y, z) min(x, min(y, z)) using namespace std; int mp[110][110]; int dp[110][110][2][20]; //x, y, 0left 1up, k次 int main() { int n, T; scanf("%d", &T); while(T--) { memset(mp, 0, sizeof(mp)); memset(dp, 0x3f3f3f3f, sizeof(dp)); scanf("%d", &n); for(int i = 1; i <= n; ++ i) { for(int j = 1; j <= n; ++ j) { scanf("%d", &mp[i][j]); } } dp[1][1][0][0] = dp[1][1][1][0] = mp[1][1]; for(int i = 2; i <= n; ++ i) { dp[1][i][0][0] = dp[1][i - 1][0][0] + mp[1][i]; dp[i][1][1][0] = dp[i - 1][1][1][0] + mp[i][1]; } for(int k = 1; k <= 15; ++ k) { for(int i = 2; i <= n; ++ i) { for(int j = 2; j <= n; ++ j) { if(k >= i || k >= j) continue; //小剪枝。抵达i行最多只能转i - 1次方向,j列同理 dp[i][j][0][k] = min3(dp[i][j][0][k], dp[i][j - 1][0][k] + mp[i][j], dp[i][j - 1][1][k - 1] + (1 << k - 1) + mp[i][j]); dp[i][j][1][k] = min3(dp[i][j][1][k], dp[i - 1][j][1][k] + mp[i][j], dp[i - 1][j][0][k - 1] + (1 << k - 1) + mp[i][j]); } } } int ans = 0x3f3f3f3f; for(int k = 0; k <= 15; ++ k) { ans = min3(ans, dp[n][n][1][k], dp[n][n][0][k]); } cout << ans << endl; } }