wenbao與記憶化搜索
記憶化搜索:
通俗地講就是搜索的形式,dp的思想
一些搜索難以完成,dp的動態轉移方程又不好寫的題,就會用到記憶化搜索,利用dp記錄路徑(相當於為dfs剪枝)用dfs進行模擬。。
啦啦啦啦啦啦,,,,,,,,,好厲害!!!!!!
@ https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1059
弱雞代碼
1 #include <string.h> 2 #include <iostream> 3#include <stdio.h> 4 using namespace std; 5 int a[4][44], dp[44][44][44][44], num[4], n; 6 bool flag[44]; 7 int dfs(int count){ 8 if(dp[num[0]][num[1]][num[2]][num[3]] != -1) 9 return dp[num[0]][num[1]][num[2]][num[3]]; 10 if(count == 5) 11 return dp[num[0]][num[1]][num[2]][num[3]] = 0; 12 int sum = 0; 13 for(int i = 0; i < 4; i++){ 14 if(num[i] == n) continue; 15 int color = a[i][num[i]]; 16 num[i] += 1; 17 if(flag[color]){ 18 flag[color] = false; 19 sum = max(sum, dfs(count-1)+1); 20 flag[color] = true; 21 } 22 else{ 23 flag[color] = true; 24 sum = max(sum, dfs(count+1)); 25 flag[color] = false; 26 } 27 num[i] -=1 ; 28 } 29 return dp[num[0]][num[1]][num[2]][num[3]] = sum; 30 } 31 int main(){ 32 while(scanf("%d", &n) && n){ 33 memset(dp, -1, sizeof(dp)); 34 memset(flag, false, sizeof(flag)); 35 memset(num, 0 ,sizeof(num)); 36 for(int i = 0; i < n; i++){ 37 for(int j = 0; j < 4; j++){ 38 cin>>a[j][i]; 39 } 40 } 41 num[0] = num[1] = num[2] = num[3] = 0; 42 cout<<dfs(0)<<endl; 43 } 44 return 0; 45 }
@ http://acm.hdu.edu.cn/showproblem.php?pid=1078
給定一個n*n的地圖,最多只能走k步並且保證下一個點的值大於原來的點,求可以得到的最大值
開始故意用純dfs試了下果然超時。。。。。
垃圾代碼:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 int a[105][105], dp[105][105], n, m; 6 int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; 7 int dfs(int r, int c){ 8 int ma = 0; 9 if(dp[r][c]<0){ 10 for(int j = 1; j <= m; j++){ 11 for(int i = 0; i < 4; i++){ 12 int rx = r + dir[i][0]*j; 13 int cx = c + dir[i][1]*j; 14 if(rx >=0 && rx < n && cx >= 0 && cx <n && a[rx][cx] > a[r][c]){ 15 ma = max(ma,dfs(rx, cx)); 16 } 17 } 18 } 19 dp[r][c] = ma + a[r][c]; 20 } 21 return dp[r][c]; 22 } 23 int main(){ 24 while(scanf("%d %d", &n, &m)){ 25 if(n == -1 && m == -1) break; 26 else{ 27 for(int i = 0; i < n; i++){ 28 for(int j = 0; j < n; j++){ 29 scanf("%d", &a[i][j]); 30 dp[i][j] = -1; 31 } 32 } 33 printf("%d\n", dfs(0, 0)); 34 } 35 } 36 return 0; 37 }
@ 玲瓏杯:::::::
http://www.ifrog.cc/acm/problem/1032
n個球放在m個盒子裏面,要求放最多球的盒子數唯一,(可以放零個球), 求最多的放法
明顯的記憶化搜索
垃圾代碼
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 #define ll long long 5 const ll mod = 998244353; 6 ll dp[505][505], n, m, num = 0; 7 ll dfs(ll he, ll qiu, ll ma){ 8 if(he == 0){ 9 if(qiu == 0) return 1; 10 else return 0; 11 } 12 if(dp[he][qiu]) return dp[he][qiu]; 13 ll mam = 0; 14 for(int i = 0; i < ma && i <=qiu; i++){ 15 mam += dfs(he-1, qiu-i, ma); 16 mam %= mod; 17 } 18 dp[he][qiu] = mam; 19 return mam; 20 } 21 int main(){ 22 cin>>n>>m; 23 for(int i = n; i >=0; i--){ 24 memset(dp, 0, sizeof(dp)); 25 num += dfs(m-1, n-i, i); 26 num %= mod; 27 } 28 cout<<num*m%mod<<endl; 29 return 0; 30 }
@ http://acm.hdu.edu.cn/showproblem.php?pid=1978
啦啦啦啦啦, 1A的感覺真是太爽了!!!可能這就是堅持的理由,,經過拼搏換來的快樂才是最大的快樂!!!!
從(0, 0) 點到(n-1, m-1) 點一共有多少種走法(只可以向右向下走)
1 #include <iostream> 2 using namespace std; 3 #define ll long long 4 const int mod = 10000; 5 int a[105][105], dp[105][105], n, m, t; 6 int dir[2][2] = {0, 1, 1, 0}; 7 int dfs(int r, int c, int sum){ 8 if(r == n-1 && c == m-1) return 1; 9 ll cot = 0; 10 if(dp[r][c] < 0){ 11 for(int i = 0; i <= sum; i++){ 12 for(int j = 0; j <= sum - i; j++){ 13 if(i == 0 && j == 0) continue; 14 int rx = r + i; 15 int cx = c + j; 16 if(rx >= 0 && rx < n && cx >= 0 && cx < m){ 17 cot += dfs(rx, cx, a[rx][cx]); 18 cot %= mod; 19 } 20 } 21 } 22 dp[r][c] = cot; 23 } 24 return dp[r][c]; 25 } 26 int main(){ 27 cin>>t; 28 while(t--){ 29 cin>>n>>m; 30 for(int i = 0; i < n; i++){ 31 for(int j = 0; j < m; j++){ 32 cin>>a[i][j]; 33 dp[i][j] = -1; 34 } 35 } 36 cout<<dfs(0, 0, a[0][0])<<endl; 37 } 38 return 0; 39 }
-------------------------------------------
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1455
關鍵在於跳的次數不會很大
1 #include "iostream" 2 #include <string.h> 3 using namespace std; 4 5 const int maxn = 30009; 6 int sum[maxn][777], num[maxn], n, d, num2[maxn]; 7 bool vis[maxn][777]; 8 9 int dd(int pos, int l) { 10 if(pos > 30000) return 0; 11 if(sum[pos][l] != -1) return sum[pos][l]; 12 sum[pos][l] = num[pos]; 13 int cnt = 0; 14 cnt = max(cnt, dd(pos+l+1-300+d, l+1)); 15 cnt = max(cnt, dd(pos+l-300+d, l)); 16 if(l+d-300 > 1) cnt = max(cnt, dd(pos+l-300-1+d, l-1)); 17 sum[pos][l] += cnt; 18 return sum[pos][l]; 19 } 20 21 int main() { 22 int x; 23 scanf("%d%d", &n, &d); 24 for(int i = 0; i < n; ++i) { 25 scanf("%d", &x); 26 num[x] ++; 27 } 28 memset(sum, -1, sizeof(sum)); 29 printf("%d\n", dd(d, 300)); 30 return 0; 31 }
只有不斷學習才能進步!
wenbao與記憶化搜索