[BZOJ1032][P1840] 祖玛 记忆化搜索 动态规划
描述 Description | |||
某天,小x在玩一个经典小游戏——zumo。 zumo游戏的规则是,给你一段长度为n的连续的彩色珠子,珠子的颜色不一定完全相同,但是,如果连续相同颜色的珠子大于等于k个,这些珠子就会消失。当然,最初的状态可能不必要直接消掉一些珠子(见样例)。现在你有无穷个所有颜色的珠子,并且你可以在任意地方插入珠子。 现在提出问题:给你一个固定的状态,你最少需要用多少个小球,才能将所有的小球消去。 |
|||
输入格式 Input Format | |||
第一行是两个整数,n (1 ≤ n ≤ 100)和k(2 ≤ k ≤5),表示有n个彩色珠子,必须连续有k个以上(包括k个)相同颜色的珠子,这些珠子才会消失。 接下来一行包含n个用空格隔开的整数,每个数在1到100之间,每个数值表示一个珠子的颜色,相同的数字意味着珠子的颜色相同。 |
|||
输出格式 Output Format | |||
一个整数,表示最少需要用多少个小球,才能让所有的小球消失。 |
http://www.cnblogs.com/AndreMouche/archive/2011/02/27/1966504.html
↑大神的程序...
状态可以通过记忆化搜索找(复习时间:记忆化搜索就是把找到的东西都存在f[i][j][cnt]里下次用这个值就不用搜了... )
f[i][j][cnt] =x 表示从i到j的珠子前有cnt个连续的紧跟在i前面的与第i个珠子相同的珠子,此时需要x个珠子可以让他们全部消失(BOOM!)
搜索时也是这三个变量(虽然记录的是cnt,但是cnt+1才是此时记录的连续的珠子的个数(加上i位置的珠子))
下面是手把手的贴心的和贴代码没两样的题解...聪明人就不要往下看了...(我找不到要点所以就把代码含义叙述了一遍)
当f[i][j][cnt] 储存有有意义的值(搜索过了)的时候,直接返回该值;
i=j时 返回k(k个珠子时可以可以消失)-(1+cnt)(把最后剩下来的珠子补成k个)
i>j时,当然不需要珠子啦...返回0
连续的珠子数(cnt+1)大于等于k时,则消去这些珠子,搜索从i+1到j个珠子(因为前面多于k的珠子自动消去所以此时f[i+1][j][0]和f[i][j][cnt]等效.....)
小于时,则搜索手动加进去一个珠子的状态,即f[i][j][cnt+1]+1和f[i][j][cnt]等效...
此时该搜的都搜了,,就需要dp来找状态的最优值...,在i和j之间找一个w,w位置的小球和i位置的一样......则
f[i][j][cnt] =min(f[i][j][cnt],f[i+1][w-1][0]+f[w][j][min(cnt+1,k-1)]);
这个应该很好理解所以我就不手把手解释了....就是消去中间的珠子然后让两边一样的珠子撞在一起再消一次,正常的祖玛方法......
最后把f[i][j][cnt]的值返回
有些地方我没写dfs(i,j,cnt)什么的但是不代表不用递归.....某个f[i][j][cnt]如果没值当然要搜索它啊...仙女教母不会自动给你初始化成正确答案的,这是搜索,醒醒!!!!而且搜索之后别忘了记忆化...所以这个鬼畜的东西才叫记忆化搜索...
欢迎神犇捉虫...虽然神犇看这么简单的题估计题解都不愿意写...
因为校对无能所以真的有什么错误我不负责任...
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 int n,k; 9 int a[110][2]={}; 10 int dd[110]={}; 11 int f[110][110][110]; 12 int fff(int b1,int b,int cnt){ 13 int &cur=f[b1][b][cnt]; 14 if(cur!=-1) return cur; 15 if(b1==b){ 16 cur=k-cnt-1; 17 return cur; 18 } 19 if(b1>b){ 20 cur=0; 21 return cur; 22 } 23 if(cnt<k-1){ 24 cur=fff(b1,b,cnt+1)+1; 25 } 26 else{ 27 if(cnt>=k-1){ 28 cur=fff(b1+1,b,0); 29 } 30 } 31 int i; 32 for(int i=b1+1;i<=b;i++){ 33 if(dd[i]!=dd[b1]) continue; 34 int value=fff(b1+1,i-1,0)+fff(i,b,min(cnt+1,k-1)); 35 if(value<cur) cur=value; 36 } 37 return cur; 38 } 39 int main(){ 40 cin>>n>>k; 41 int tail=-1; 42 int sumn=0; 43 for(int i=1;i<=n;i++){ 44 cin>>dd[i]; 45 } 46 memset(f,-1,sizeof(f)); 47 cout<<fff(1,n,0)<<endl; 48 return 0; 49 }