Description
精致细腻的背景,外加神秘的印加音乐衬托,仿佛置身在古老国度里面,进行一个神秘的游戏——这就是著名的祖玛游戏。祖玛游戏的主角是一只石青蛙,石青蛙会吐出各种颜色的珠子,珠子造型美丽,并且有着神秘的色彩,环绕着石青蛙的是载着珠子的轨道,各种颜色的珠子会沿着轨道往前滑动,石青蛙必需遏止珠子们滚进去轨道终点的洞里头,如何减少珠子呢?就得要靠石青蛙吐出的珠子与轨道上的珠子相结合,颜色相同者即可以消失得分。直到轨道上的珠子通通都被清干净为止。
或许你并不了解祖玛游戏,没关系。这里我们介绍一个简单版本的祖玛游戏规则。一条通道中有一些玻璃珠,每个珠子有各自的颜色,如图1所示。玩家可以做的是选择一种颜色的珠子(注意:颜色可以任选,这与真实游戏是不同的)射入某个位置。
祖玛示意图(1)
中玩家选择一颗蓝色珠子,射入图示的位置,于是得到一个图3的局面。
祖玛示意图(2)
祖玛示意图(3)
当玩家射入一颗珠子后,如果射入的珠子与其他珠子组成了3颗以上连续相同颜色的珠子,这些珠子就会消失。例如,将一颗白色珠子射入图4的位置,就会产生3颗眼色相同的白色珠子。这3颗珠子就会消失,于是得到图5的局面。
祖玛示意图(4)
祖玛示意图(5)
需要注意的是,图1中的3颗连续的黄色珠子不会消失,因为并没有珠子射入其中。
珠子的消失还会产生连锁反应。当一串连续相同颜色的珠子消失后,如果消失位置左右的珠子颜色相同,并且长度大于2,则可以继续消失。例如,图6中,射入一颗红色珠子后,产生了3颗连续的红色珠子。当红色珠子消失后,它左右都是白色的珠子,并且一共有四颗,于是白色珠子也消失了。之后,消失位置的左右都是蓝色珠子,共有3颗,于是蓝色珠子也消失。最终得到图7的状态。
注意:图7中的3颗黄色珠子不会消失,因为蓝色珠子消失的位置一边是紫色珠子,另一边是黄色珠子,颜色不同。
祖玛示意图(6)
祖玛示意图(7)
除了上述的情况,没有其他的方法可以消去珠子。
现在,我们有一排珠子,需要你去消除。对于每一轮,你可以自由选择不同颜色的珠子,射入任意的位置。你的任务是射出最少的珠子,将全部珠子消去。
Input
第一行一个整数n(n ≤500),表示珠子的个数。第二行n个整数(32位整数范围内),用空格分割,每个整数表示一种颜色的珠子。
Output
一个整数,表示最少需要射出的珠子个数。
Sample Input
9
1 1 2 2 3 3 2 1 1
Sample Output
1
以下是代码,但是时间复杂度太高了...N>10基本就算不出来,如果有更好的算法可以给我留言~
/* insert()方法:将串str的每个位置前插入一个相同颜色的珠子,消去后将剩余的串pstr再递归调用insert(),返回射出珠子数最小值
* clear()方法:在i前射入同颜色珠子,返回经消除后的串
* 类hasCount:存储计算过的str对应的minCount,以重复利用,这是后来加入的优化方案,以空间换时间
*/
import java.util.ArrayList;
import java.util.Scanner;
public class zuma {
static ArrayList<hasCount> arr=new ArrayList<hasCount>();
static int w=0;
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] str=new int[n];
for(int i=0;i<n;i++){
str[i]=sc.nextInt();
}
int minCount=insert(str);
System.out.println(minCount);
}
public static int insert(int[] str){ //再str每个位置之前射入珠子
if(str.length==0) return 0; //消除完毕
int minCount=Integer.MAX_VALUE;
for(int i=0;i<str.length;i++){
if(i>0 && str[i]==str[i-1]) continue;
int[] pstr=clear(str, i);
int count=0;
boolean flag=false;
for(int j=0;j<arr.size();j++){ //查看是否已经计算过
hasCount hc=(hasCount)arr.get(j);
if(pstr.length!=hc.getStr().length) continue;
int u=0;
for(;u<pstr.length;u++){
if(pstr[u]!=hc.getStr()[u]) break;
}
if(u==pstr.length){
count=hc.getMinCount();
flag=true;
w++;
break;
}
}
if(!flag){ //递归insert计算并保存
count=insert(pstr);
if(pstr.length!=0){
hasCount hc=new hasCount();
hc.setStr(pstr);
hc.setMinCount(count);
arr.add(hc);
}
}
if(minCount>count){
minCount=count;
}
}
return minCount+1;
}
public static int[] clear(int[] str, int i){ //在i处放入相同颜色的珠子后进行消除
int p=i,q=i+1; //左,右标记
int count=0; //重复颜色数
int[] pstr;
while(q<str.length && str[p]==str[q]){
count++;
q++;
}
if(count==0){ //一个珠子的情况
pstr=new int[str.length+1];
int index=0;
for(int u=0;u<=p;u++){
pstr[index++]=str[u];
}
pstr[index++]=str[p];
for(int u=p+1;u<str.length;u++){
pstr[index++]=str[u];
}
return pstr;
}else{ //两个珠子的情况
p--;
count=3;
int p2=0,q2=0;
while(p>=0 && q<=str.length-1 && count>=3){
p2=p;q2=q; //标记原来的位置
int count1=0,count2=0;
count=0;
int temp=str[p2];
while(p2>=0 && str[p2]==temp){
count1++;
p2--;
}
while(q2<=str.length-1 && str[q2]==temp){
count2++;
q2++;
}
count=count1+count2;
if(count1!=0 && count2!=0 && count>=3){
p=p2;q=q2;
}
}
int index=0;
pstr=new int[str.length-(q-p-1)];
for(int u=0;u<=p;u++){
pstr[index++]=str[u];
}
for(int u=q;u<=str.length-1;u++){
pstr[index++]=str[u];
}
if(index==0) pstr=new int[0];
return pstr;
}
}
}
class hasCount{ //计算过的子串
private int[] str=new int[10];
private int minCount=0;
public int[] getStr() {
return str;
}
public void setStr(int[] str) {
this.str=new int[str.length];
for(int i=0;i<str.length;i++){
this.str[i]=str[i];
}
}
public int getMinCount() {
return minCount;
}
public void setMinCount(int minCount) {
this.minCount = minCount;
}
}