题目描述
wlswls在玩一个游戏。
wlswls有一个nn行mm列的棋盘,对于第ii行第jj列的格子,每过T[i][j]T[i][j]秒会在上面出现一个糖果,第一次糖果出现在第T[i][j]T[i][j]秒,糖果仅会在出现的那一秒存在,下一秒就会消失。
假如wlswls第kk秒在第ii行第jj列的格子上,满足T[i][j] | kT[i][j]∣k,则wlswls会得到一个糖果。
假如当前wlswls在第ii行第jj列的格子上,那么下一秒他可以选择往上下左右走一格或停在原地。
现在请问wlswls从指定的SS出发到达指定的TT,并且在路上得到至少CC个糖果最少需要多少时间?
wlswls在SS的初始时间为第00秒。
输入描述
第一行三个整数nn,mm,CC。
接下来nn行,每行m个整数T[i][j]T[i][j]。
接下来四个整数xsxs, ysys, xtxt, ytyt,其中(xs, ys)(xs,ys)表示SS,(xt, yt)(xt,yt)表示tt。
1 \leq n, m, T[i][j] \leq 101≤n,m,T[i][j]≤10
1 \leq C \leq 10181≤C≤1018
1 \leq xs, xt \leq n1≤xs,xt≤n
1 \leq ys, yt \leq m1≤ys,yt≤m
输出描述
一行一个整数表示答案。
样例输入 1
1 3 2 1 2 3 1 1 1 3
样例输出 1
3
思路:
定义状态 dp[i][j][t] 表示在t秒时 i,j位置最多可以获得的豆豆数量,
显然有以下的状态转移:
dp[i][j][t] = max(dp[i][j][t],dp[i-1][j][t-1]);
dp[i][j][t] = max(dp[i][j][t],dp[i][j-1][t-1]);
dp[i][j][t] = max(dp[i][j][t],dp[i+1][j][t-1]);
dp[i][j][t] = max(dp[i][j][t],dp[i][j+1][t-1]);
dp[i][j][t] = max(dp[i][j][t],dp[i][j][t-1]);
因为所求的是指定位置豆豆数量大于等于c的最小时间,
那么我们不妨放弃第三维度,多开一个拷贝数组来存上一秒的状态,每一次加一个时间来转移。
然后当指定位置豆豆数量大于等于c的时候
直接结束转移,输出当前的时间。
细节见代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n, m; int t[30][30]; int c; int sx, sy, tx, ty; int dp[12][12]; int b[12][12]; int main() { //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); gbtb; cin >> n >> m >> c; repd(i, 1, n) { repd(j, 1, m) { cin >> t[i][j]; } } cin >> sx >> sy >> tx >> ty; int step; memset(dp, -1, sizeof(dp)); dp[sx][sy] = 0; // cout << sx << " " << sy << endl; for (step = 1; ; step++) { repd(i, 1, n) { repd(j, 1, m) { b[i][j] = dp[i][j]; // 把上一秒的状态全部保存好 } } repd(i, 1, n) { repd(j, 1, m) { // 当前状态 dp[i][j] 可以从5个状态转变来,但是dp[i][j]->dp[i][j] 可以不写状态转移(没意义,原地加1会在后面处理) if (i >= 2) { dp[i][j] = max(dp[i][j], b[i - 1][j]); } if (i <= n - 1) { dp[i][j] = max(dp[i][j], b[i + 1][j]); } if (j >= 2) { dp[i][j] = max(dp[i][j], b[i][j - 1]); } if (j <= m - 1) { dp[i][j] = max(dp[i][j], b[i][j + 1]); } if (step % t[i][j] == 0) { if (dp[i][j] >= 0) // 可以到达,即 >=0 ,因为dp[sx][sy]=0 { dp[i][j]++; } } } } // repd(i, 1, n) // { // repd(j, 1, m) // { // cout << dp[i][j] << " "; // } // cout << endl; // } if (dp[tx][ty] >= c) { break; } } cout << step << endl; return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }