題目描述:
題目大意:有n個物品排成一排,從左往右第i個價值為a[i],有兩個人從左往右輪流取物品。第乙個人可以拿一或兩個物品。如果前乙個人拿了k個,下乙個人只能拿k或k+1個。如果剩下的物品不夠拿,就結束。問如果大家都採取最優策略,那麼先手拿的物品的價值最多能比後手多多少。(1≤n≤20000)
樣例輸入:
1樣例輸出: 題目分析:3 1 3 2
考場總結:考試時,覺得這道題特別像前面做得一道題分玩具,於是按照以前那個思路寫dp,結果沒寫對,然後用同樣的思路寫了個暴力dfs,30分。結果考完評講的時候,發現我的**只須將每次dfs返回的值記錄下來,記憶化一下就滿分了!!!論30分與100分的差距~~~其實考試的時候主要是沒有想到狀態有重複。
分析:
搜尋:其實每個人每次的選擇面臨的決策是一樣的,都是想使自己拿的最大。當上乙個人拿到了i且是通過拿到k個拿到的,當前拿的人就只有拿k個或拿k+1個兩種選擇。當前多的價值就是當前人拿的k個的價值和減去剩下部分能拿出的最大情況(另乙個人會想拿的最大,即dfs的返回值)。於是以此dfs,然後記錄下來,記憶化搜尋一下。
dp:設dp[i][k]表示從第i個物品開始先手拿k個後最多能比後手多取的價值,則:
dp[i][k]=sum[i~i+k-1]+max(dp[i+k][k],dp[i+k+1][k+1])
注意到k最多取到200(20000<1+2+……+200),所以第二維只用開到200即可。
ps:其實dp和dfs運用的思想是一樣的。dp方法懶得寫,於是dp的分析和**都來自於cdsszjj的部落格的博文noip模擬 game 【博弈論】【動態規劃】
附**:
1、搜尋:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
const
int n=20100;
int t,n,a[n],sum[n],dp[n][210];
int readint()
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}inline
int dfs(int po,int k,int w)//po代表前乙個人拿到了po,且是通過k拿的,w是那一段區間和
int main()
return
0;
}
2、dp:
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using
namespace
std;
int getint()
const
int n=20005,k=205;
int t,n;
ll a[n],dp[n][k];
int main()
return
0;}
動態規劃 記憶化搜尋
記憶化搜尋顧名思義是在搜尋的過程中通過記錄搜尋的中間狀態從而達到減少重複搜尋的方法,通常用在搜尋樹 現重複子節點的情況。例題 滑雪 給定乙個r行c列的矩陣,表示乙個矩形網格滑雪場。矩陣中第 i 行第 j 列的點表示滑雪場的第 i 行第 j 列區域的高度。乙個人從滑雪場中的某個區域內出發,每次可以向上...
動態規劃之記憶化搜尋
一.動態規劃 動態規劃 dynamic programming 與 分治思想 有些相似,都是利用將問題分 為子問題,並通過合併子問題的解來獲得整個問題的解。於 分治 的不同之處在 於,對於乙個相同的子問題動態規劃演算法不會計算第二次,其實現原理是將每乙個計算過的子問題的值儲存在乙個表中。二.記憶化搜...
動態規劃 記憶化搜尋(滑雪)
給定乙個r行c列的矩陣,表示乙個矩形網格滑雪場。矩陣中第 i 行第 j 列的點表示滑雪場的第 i 行第 j 列區域的高度。乙個人從滑雪場中的某個區域內出發,每次可以向上下左右任意乙個方向滑動乙個單位距離。當然,乙個人能夠滑動到某相鄰區域的前提是該區域的高度低於自己目前所在區域的高度。下面給出乙個矩陣...