DFS——记忆化搜索——动态规划
以洛谷P1802 ?5倍經驗日 為例
https://www.luogu.org/problem/show?pid=1802
題目背景
現在樂斗有活動了!每打一個人可以獲得5倍經驗!absi2011卻無奈的看著那一些比他等級高的好友,想著能否把他們干掉。干掉能拿不少經驗的。
題目描述
現在absi2011拿出了x個迷你裝藥物(嗑藥打人可恥….),準備開始與那些人打了
由于迷你裝一個只能管一次,所以absi2011要謹慎的使用這些藥,悲劇的是,沒到達最少打敗該人所用的屬性藥了他打人必輸>.<所以他用2個藥去打別人,別人卻表明3個藥才能打過,那么相當于你輸了并且這兩個屬性藥浪費了。
現在有n個好友,有輸掉拿的經驗、贏了拿的經驗、要嗑幾個藥才能打過。求出最大經驗(注意,最后要乘以5)
輸入輸出格式
輸入格式:
第一行兩個數,n和x
后面n行每行三個數,分別表示輸了拿到的經驗(lose[i])、贏了拿到的經驗(win[i])、打過要至少使用的藥數量(use[i])。
輸出格式:
一個整數,最多獲得的經驗
輸入輸出樣例
輸入樣例#1:6 8 21 52 1 21 70 5 21 48 2 14 38 3 14 36 1 14 36 2 輸出樣例#1:
1060
說明
【Hint】
五倍經驗活動的時候,absi2011總是吃體力藥水而不是這種屬性藥>.<
【數據范圍】
對于10%的數據,保證x=0
對于30%的數據,保證n<=10,x<=20
對于60%的數據,保證n<=100,x<=100, 10<=lose[i], win[i]<=100,use[i]<=5
對于100%的數據,保證n<=1000,x<=1000,0<lose[i]<=win[i]<=1000000,0<=use[i]<=1000
明顯的一個01背包
先說本題要注意的地方
1、答案要用long long
2、如果是體力為0也可以打,+lose[i]
裸的搜索版本 ,TLE
now表示當前搜索哪個對手,expe表示當前經驗值,potion表示剩下的藥水瓶數
#include<cstdio> #include<algorithm> using namespace std; int n,x; int lose[1001],win[1001],need[1001]; long long ans; void dfs(int now,long long expe,int potion) {ans=max(ans,expe);if(now>n) return;if(need[now]<=potion) dfs(now-1,expe+win[now],potion-need[now]);dfs(now-1,expe+lose[now],potion); } int main() {scanf("%d%d",&n,&x);for(int i=1;i<=n;i++)scanf("%d%d%d",&lose[i],&win[i],&need[i]);dfs(n,0,x);printf("%lld",ans*5); }有人可能要問為什么搜索dfs過程的now是從n到1,能不能從1到n?
答案是完全可以,因為搜索的結果與搜索順序無關
下面的記憶化搜索now也可以改成從1到n
記憶化搜索版本??55ms / ?23.51MB
可以發現主要的區別就是dfs有了返回值
#include<cstdio> #include<algorithm> using namespace std; int n,x; int lose[1001],win[1001],need[1001]; long long f[1002][1001]; long long dfs(int now,int potion) {if(!now) return 0;//邊界if(f[now][potion]) return f[now][potion];//關鍵在這一句,如果這一狀態在之前已經計算過了,直接returnif(need[now]<=potion) f[now][potion]=max(f[now][potion],dfs(now-1,potion-need[now])+win[now]); f[now][potion]=max(f[now][potion],dfs(now-1,potion)+lose[now]);return f[now][potion]; } int main() {scanf("%d%d",&n,&x);for(int i=1;i<=n;i++)scanf("%d%d%d",&lose[i],&win[i],&need[i]);printf("%lld",dfs(1,x)*5); }DP版本??30ms /??23.5MB
由此可以看到DP與記憶化搜索的不同之處:
記憶化搜索,本質還是搜索,所以它的更新是從下往上的,即由后一個狀態來更新
DP的更新是從上往下的,即由前一個狀態來更新
所以轉化成DP時,要將記憶化搜索的更新過程反過來
#include<cstdio> #include<algorithm> using namespace std; int n,x; int lose[1001],win[1001],need[1001]; long long f[1001][1001]; int main() {scanf("%d%d",&n,&x);for(int i=1;i<=n;i++)scanf("%d%d%d",&lose[i],&win[i],&need[i]);for(int i=1;i<=n;i++)for(int j=x;j>=0;j--)if(j>=need[i]) f[i][j]=max(f[i-1][j-need[i]]+win[i],f[i-1][j]+lose[i]);else f[i][j]=f[i-1][j]+lose[i];printf("%lld",f[n][x]*5); }?
DP版本的優化,壓去第一維??19ms /??16.04MB
#include<cstdio> #include<algorithm> using namespace std; int n,x; int lose[1001],win[1001],need[1001]; long long f[1001]; int main() {scanf("%d%d",&n,&x);for(int i=1;i<=n;i++)scanf("%d%d%d",&lose[i],&win[i],&need[i]);for(int i=1;i<=n;i++)for(int j=x;j>=0;j--)if(j>=need[i]) f[j]=max(f[j-need[i]]+win[i],f[j]+lose[i]);else f[j]+=lose[i];printf("%lld",f[x]*5); }?
?
#include<cstdio> #include<algorithm> using namespace std; int n,x; int lose[1001],win[1001],need[1001]; long long f[1002][1001]; long long dfs(int now,int potion) {if(now>n) return 0;if(need[now]<=potion) {if(f[now+1][potion-need[now]]) f[now][potion]=max(f[now][potion],f[now+1][potion-need[now]]);else f[now][potion]=max(f[now][potion],dfs(now+1,potion-need[now])+win[now]); }if(f[now+1][potion]) f[now][potion]=max(f[now][potion],f[now+1][potion]);else f[now][potion]=max(f[now][potion],dfs(now+1,potion)+lose[now]);return f[now][potion]; } int main() {scanf("%d%d",&n,&x);for(int i=1;i<=n;i++)scanf("%d%d%d",&lose[i],&win[i],&need[i]);printf("%lld",dfs(0,x)*5); } 錯誤的記憶化搜索求助路過大佬
轉載于:https://www.cnblogs.com/TheRoadToTheGold/p/6367147.html
總結
以上是生活随笔為你收集整理的DFS——记忆化搜索——动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: json解析网站
- 下一篇: 阿里云服务器1M带宽是多少