dp的刷表法和填表法


dp的刷表法和填表法

參考:

動態規划刷表法 - acmer_xue的博客 - CSDN博客
http://blog.csdn.net/qq_30241305/article/details/52198780

 

一.先簡單講下什么是填表法,什么是刷表法。

填表法 :就是一般的動態規划,當前點的狀態,可以直接用狀態方程,根據之前點的狀態推導出來。

刷表法:由當前點的狀態,更新其他點的狀態。需要注意:只用當每個狀態所依賴的狀態對它的影響相互獨立。

二.通過例題看刷表

鏈接:http://exam.upc.edu.cn/problem.php?id=2383

題意:三個數,T表示最大的飽腹值,A表示吃a可以增加的飽腹值,B表示吃b可以增加的飽腹值。ab都有無窮多個。初始狀態是0,可以有一次通過喝水,來使飽腹值減少一半(向下取整)的機會。

分析:首先按照一般的動態規划,會有問題。

為什么不能用填表法?

因為當前狀態既與之前的狀態有關,又與之后的狀態有關。當前的狀態與dp[ i - a],dp[i - b],dp[i * 2]有關。所以用刷表法,來直接更新狀態。

此題中,喝水后的狀態可以在喝水的基礎上計算。及可以先計算所有喝水前的狀態,再計算所有喝水后的狀態。喝水前的狀態可以更新喝水后的狀態。

另:注意,本題中飽腹值不能超過最大值T

代碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <sstream>
 5 #include <string>
 6 #include <algorithm>
 7 #include <list>
 8 #include <map>
 9 #include <vector>
10 #include <queue>
11 #include <stack>
12 #include <cmath>
13 #include <cstdlib>
14 using namespace std;
15 int dp[5000005][2];
16 int main()
17 {
18     //freopen("in.txt","r",stdin);
19     int p,a,b;
20     scanf("%d%d%d",&p,&a,&b);
21     dp[0][0] = dp[0][1] = 1;
22     for(int j = 0; j < 2; j ++)
23     {
24         for(int i = 0; i <= p; i ++)
25         {
26             if(dp[i][j])
27             {
28                 if(i+ a <= p)
29                     dp[i + a][j] = 1;
30                 if(i + b <= p)
31                     dp[i + b][j] = 1;
32                 if(j == 0)
33                     dp[i / 2][1] = 1;
34             }
35         }
36     }
37  
38  
39     int ans;
40     for(int i = p; i >= 0; i --)
41     {
42         if(dp[i][0] || dp[i][1])
43         {
44             ans = i;
45             break;
46         }
47     }
48     printf("%d\n",ans);
49  
50     return 0;
51 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM