hdu1978 How many ways(記憶化搜尋)
阿新 • • 發佈:2019-02-06
題意:中文題。
思路:注意這題題中說“當機器人選擇了一條可行路徑後,當他走到這條路徑的終點時,他將只有終點所標記的能量”。剛開始這條件我就看了半天,這句話中明確指出大的能量轉移(不包括每走一步的能量減一)只有一個條件可以觸發,那就是到達終點,其他沒說明的就表明無法觸發。(有異議的歡迎撕逼,這的確是題的問題)。然後就開始寫,每次dfs傳遞能量值pow,每遞迴一次能量減一,中間一個if就可以搞定。然而怎麼也搞不出答案,後來手算了幾遍發現沒問題,這是題意理解錯了,然後看了別人題解才發現是題錯了。。
一個最大的變化就是所到路徑上的點也可以發生能量轉移,接著就在原程式上改。我用的方法是一步一步走判斷,加了這個條件後dfs裡就相當於有兩個dfs序列執行,問題就來了,哪個dfs放在前面?執行了一個dfs就會對其餘節點產生變化,而另一個是要求變化以前的值。無奈,想不出好法子,看了別人的方法。
這種搜尋方式相當於列舉吧,列舉所有的能量值,當然是加了這種變化後才有這種效果。為毛我就沒想出來呢???[尼克揚的微笑]
這也給了我個啟示,一個好的搜尋方式是做出搜尋題的關鍵。
#include <stdio.h> #include <algorithm> #include <stdlib.h> #include <string.h> #include <iostream> #include <queue> using namespace std; typedef long long LL; const int N = 105; const int INF = 0x3f3f3f3f; int n, m, G[N][N], dp[N][N]; bool check(int x, int y) { if(x>=1 && x<=n && y>=1 && y<=m) return true; else return false; } int dfs(int x, int y) { if(dp[x][y] > 0) return dp[x][y]; else { if(x==n && y==m) return 1; for(int i = 0; i <= G[x][y]; i++) { for(int j = 0; j <= G[x][y]; j++) { if(i==0 && j==0) continue; if(check(x+i, y+j) == false) continue; if(i+j > G[x][y]) continue;//沒能量走不到 dp[x][y] = (dp[x][y]+dfs(x+i, y+j))%10000;//注意這裡必須先與求一下餘,處理比較大的數耗時較多,否則超時,那後面就不用再求了 } } } return dp[x][y]; } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &G[i][j]); memset(dp, 0, sizeof(dp)); printf("%d\n", dfs(1, 1)); } return 0; }
再貼上我的失敗程式碼吧,就如上面所說:
#include <stdio.h> #include <algorithm> #include <stdlib.h> #include <string.h> #include <iostream> #include <queue> using namespace std; typedef long long LL; const int N = 105; const int INF = 0x3f3f3f3f; int n, m, G[N][N], dp[N][N]; int dir[2][2] = {{1, 0}, {0, 1}}; bool check(int x, int y) { if(x>=1 && x<=n && y>=1 && y<=m) return true; else return false; } int num = 0; int dfs(int x, int y, int pow) { if(dp[x][y] > 0) return dp[x][y]; else { if(((x==n)&&(y==m)))//到達終點 { printf("[%d]\n", num++); dp[x][y] = 1; return 1; } int sum = 0; //dp[x][y] = 0; for(int i = 0; i < 2; i++) { int xx = x+dir[i][0]; int yy = y+dir[i][1]; if(check(xx, yy))//如果找到新節點 { if(pow == 0) { sum+=dfs(xx, yy, G[xx][yy]); } else { sum+=dfs(xx, yy, pow-1); sum+=dfs(xx, yy, G[xx][yy]);//序列執行 } } } dp[x][y] = sum; return dp[x][y]; } } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &G[i][j]); memset(dp, 0, sizeof(dp)); // pow = G[1][1]; printf("%d\n", dfs(1, 1, G[1][1])); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { printf("%d ", dp[i][j]); } printf("\n"); } } return 0; }