HDU 6212 Zuma ACM/ICPC 2017 Qingdao Online(区间dp)

来源:互联网 发布:淘宝修改密码在哪里 编辑:程序博客网 时间:2024/06/05 14:31

Zuma

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 170    Accepted Submission(s): 27

Problem Description

Think about the Zuma Game. You have a row of at most 200 black(0) or white(1) balls on the table at the start. Each three consecutive balls never share the same colour. You also have infinite amount of black and white balls in your hand. On each turn, you can choose a ball in your hand and insert it into the row, including the leftmost place and the rightmost place. Then, if there is a group of three of more balls in the same colour touching, remove these balls. Keep doing this until no more balls can be removed.
Find the minimal balls you have to insert to remove all the balls on the table.

Input

The first line of input contains an integer T (1T100) which is the total number of test cases.
Each test case contains a line with a non-empty string of 0 and 1 describing the row of balls at the start.

Output

For each test case, output the case number and the minimal balls required to insert in a line.

Sample Input

410101101001001100100100101001101011001100

Sample Output

Case #1: 4Case #2: 3Case #3: 3Case #4: 2

Source

2017 ACM/ICPC Asia Regional Qingdao Online



        Zuma游戏,相信大家都玩过,但是可能不知道它的名字罢了。

        大致题意是每个珠子只有黑白两种颜色(其实多一点颜色也无所谓),然后一旦有三个及以上的同色珠子连在一起,那么就会自动消除同色的珠子。数据保证一开始没有三个连续的同色珠子,然后你每次可以选择一个颜色的珠子发射到任意位置,如果出现三同色那么消除,并且会发生连锁反应,问最后至少需要发射几个珠子才能使得所有珠子都被删除。

        赛后才听说这是一道原题,POJ 2915,而且是弱化版本,那题是连续M个同色才能删除,而且不保证一开始没有连续M个以上的同色珠。原题才真正像是我们玩的游戏。但是原题的做法我并看不懂,所以只能另寻他法。

        原题是区间dp,所以我们这里也考虑区间dp。首先我们可以把同色珠子合并成颜色段,每段有两个参数,段的颜色和珠子数量。然后,由于会发生连锁反应,所以说最少的珠子肯定是体现在这个连锁反应上。对于两段不是连在一起的同色珠子i、j,消除以i、j为首尾的区间的珠子段,可以考虑先消除[i+1,j-1]区间内的珠子段,再看i、j的珠子数量之和,如果大于等于3,那么连锁删除没有代价,如果为2,那么还需要发射一个代价为1。所以,有状态转移方程dp[i][j]=min(dp[i][j],dp[i+1][j-1]+(t[i]+t[j]==2?1:0)(c[i]==c[j]),其中t[i]表示第i个颜色段的珠子数量,c[i]表示第i个颜色段的颜色。当然再配合区间dp通用的转移方程:dp[i][j]=min(d[i][j],dp[i][k]+dp[k+1][j])(i<=k<j)。

        看似已经很完善了,但是一测样例会发现,第四个数据并不能过,而且是应为方法的问题。可以说这题样例还是很仁慈的,能够让你发现漏洞。分析样例4,我们发现,它并不是简单的两个区间合并,它还要考虑一个中间点。由于是要三个同色珠相连才能消除,所以不免会会出现首尾和中间三点同色的情况。如果中间点数量为1,收尾也有一个数量为1(或者两个都为1这里考虑其中一个为1),那么正常消除的时候,消除这三个段可选的方案是合并i+1到k-1再添加一个珠子,之后再单独处理j,或者先处理k、j再单独处理i,这样额外至少添加两个珠子,但是我们完全可以先合并i+1到k-1,再合并k+1到j-1,最后i、j、k连在一起连锁消除。有转移方程dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k+1][j-1])其中满足t[i]+t[k]和t[j]+t[k]至少一个小于3而且i、j、k三段同色。

        如此一来,我么就可以在O(N^3)的时间复杂度内完成此题,恰好符合。最后拓展一下,如果是四个一消,按照这个思路,应该会有四点同色,然后三段合并剩下点连锁消除的情况,更多时也是这样,但是时间复杂度相应的也上去了。如果想更好的解这道题,还是建议取看看POJ 2915,反正我菜不太懂……具体见代码:

#include<bits/stdc++.h>#define inf 0x3f3f3f3f#define N 210using namespace std;int dp[N][N],tot,n;short t[N];char s[N];bool c[N];int main(){    int T_T,T=0;    cin>>T_T;    while(T_T--)    {        scanf("%s",s);        tot=0; n=strlen(s);        for(int i=1;i<=n;i++)        {            bool x=s[i-1]-48;            if (i==1||x!=c[tot]) c[++tot]=x,t[tot]=1;                            else t[tot]++;        }        memset(dp,inf,sizeof(dp));        for(int i=1;i<=tot;i++) dp[i][i]=t[i]==1?2:1;        for(int len=2;len<=tot;len++)            for(int i=1;len+i-1<=tot;i++)            {                int j=i+len-1;                if (c[i]==c[j])                    dp[i][j]=dp[i+1][j-1]+(t[i]+t[j]==2?1:0);                for(int k=i;k<j;k++)                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);                if (c[i]==c[j])                    for(int k=i+1;k<j;k++)                        if (c[i]==c[k]&&(t[i]+t[k]<3||t[j]+t[k]<3))                            dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k+1][j-1]);            }        printf("Case #%d: %d\n",++T,dp[1][tot]);    }}

阅读全文
0 0
原创粉丝点击