1. 程式人生 > >hdu 4778 Gems Fight!(博弈+記憶化搜索)

hdu 4778 Gems Fight!(博弈+記憶化搜索)

%d ide printf 魔法 最優 選擇 每次 logs pac

題目鏈接:hdu 4778 Gems Fight!

題意:

有B個袋子,每個袋子裏有一些小球,每個小球有一個顏色,現在Alice和Bob輪流選袋子。

每次選一個袋子,並將袋子裏的小球放進鍋裏,如果鍋裏的相同顏色的小球個數大於等於S,那麽當前選袋子的人

就會得到一個由這S個融合而成的魔法寶石(每次可以得到多個),並且再獲得一次選袋子的機會。

現在Alice先手,問雙方都采取最優的策略,Alice與Bob最後得到的寶石相差多少個。

題解:

這種博弈,無法求sg,也沒有結論,顯然就是搜索了。不過這裏爆搜的話肯定會T,

所以加一個記憶化就行了。dp[i][j]表示第i個人當前袋子狀態為j時的最優選擇的答案。

然後搜一下就行了。

技術分享
 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 #define mst(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 
 6 const int N=22,inf=100000;
 7 int G,B,S,cnt[10];
 8 vector<int>bag[N];
 9 
10 int get(int idx,int *cnt)
11 {
12     int ans=0;
13     for
(auto &it:bag[idx])if(++cnt[it]>=S)ans++,cnt[it]-=S; 14 return ans; 15 } 16 17 int dp[2][1<<21]; 18 19 int dfs(int val,int turn,int now,int *ct,int v) 20 { 21 if(turn>B)return val; 22 if(dp[now][v]!=-inf)return dp[now][v]+val; 23 int cnt[10],vis=v,bst=now?inf:-inf; 24
F(i,1,B)if((vis&(1<<(i-1)))==0) 25 { 26 memcpy(cnt,ct,sizeof(cnt)); 27 vis|=(1<<(i-1)); 28 int tmp=get(i,cnt),tbst; 29 if(tmp)tbst=dfs(now?-tmp:tmp,turn+1,now,cnt,vis); 30 else tbst=dfs(0,turn+1,now^1,cnt,vis); 31 vis^=(1<<(i-1)); 32 bst=now?min(tbst,bst):max(tbst,bst); 33 } 34 dp[now][v]=bst; 35 return bst+val; 36 } 37 38 int main(){ 39 while(scanf("%d%d%d",&G,&B,&S),G+B+S) 40 { 41 F(i,1,B)bag[i].clear(); 42 int U=(1<<B)-1; 43 F(j,0,1)F(i,0,U)dp[j][i]=-inf; 44 F(i,1,G)cnt[i]=0; 45 F(i,1,B) 46 { 47 int num,x; 48 scanf("%d",&num); 49 F(j,1,num)scanf("%d",&x),bag[i].push_back(x); 50 } 51 printf("%d\n",dfs(0,1,0,cnt,0)); 52 } 53 return 0; 54 }
View Code

hdu 4778 Gems Fight!(博弈+記憶化搜索)