UESTC Training for Search Algorithm——K

Can You Help God Wu

Description

 

There is a boy named God Wu in UESTC ACM team. One day he is asked to finish a task. The task is that he has to paint a wall as the given pattern. The wall can be represented as a 2*n grid and each grid will be painted only one color. You know God Wu is a God, so he has a brush which could paint a rectangular area of the wall at a single step. As we all know, the paint could be overlap and the newly painted color will replace the older one.
God Wu is so lazy that he always want to finish something in the least steps. At first, the wall was not painted until God Wu paint some colors on it. For a given pattern of the wall, God Wu has to find out the minimum possible number of painting steps to make the wall the same as the given pattern.

 

Input

 

In the input file, the first line contains the number of test cases.
For each test case, the first contains only one integer n (1<=n<=8) indicating the length of the wall.
Then follows two lines, denoting the expected pattern of the wall. Every grid is painted by a color which is represented by a single capital letter. You can see the Input Sample for more details.

 

Output

 

For each test case, output only one integer denoting the minimum number of steps.

 

Sample Input

 

3
3
ABA
CBC
3
BAA
CCB
3
BBB
BAB

 

Sample Output

 

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

 

 

/*算法思想:
  BFS,用最终的状态逆着BFS,直到板上没有颜色为止
  保存状态:如果这个格子已经被还原为无色了,为0,如果没有,为1,再将这个二进制数转换成
  十进制数,作为状态。然后每次BFS的时候,要是能够直接刷掉宽度为2的矩形,就刷掉宽度为2的
  矩形,要是不能就刷掉宽度为1的矩形。为了避免重复的情况,又加了一个数组用来判断这个状态
  是否搜索过。不知道是哪里挂了,我自己出了很多组数据全部通过了,各种情况都涉及到了,但是
  还是不知道具体错在哪里了,真的很纠结,这道题做的也很晚,跟棋盘游戏一样,这几天老是各种
  事情,昨晚上才有时间刷题,结果不知道怎么回事老是不能过。还是附上代码吧,希望能得点分
*/

/*CODE*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
char s[2][10];
//存储2^i次方在zl[i]中
const int zl[18]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072};
int n,ans;
char hash[131075][2][10];  //存储具体的状态
char v[1311075];  //用于判断状态是否搜索过
struct data  //BFS队列每个节点
{
    int n;  //状态的hash值
    int step;  //到达这个状态花了多少步
};
int cal(int a[][10])  //计算状态的hash值
{
    int temp=0;
    for(int i=0;i<2;i++)
      for(int j=0;j<n;j++)
          temp+=a[i][j]*zl[i*n+j];
    return temp;
}
void add(int temp,char a[][10])  //添加一个具体的状态
{
    for(int i=0;i<2;i++)
        for(int j=0;j<n;j++)
            hash[temp][i][j]=a[i][j];
}
int find(char s[][10],int row,int k)  //在第row行找和第k个元素相同的最远的那点
{
    char ch=s[row][k];
    while((k+1<n) && (s[row][k+1]=='*' || s[row][k+1]==ch))  //被还原了的区域可以为各种颜色
        k++;
    return k;
}
bool findchar(char s[][10],int row,char ch,int st,int en)  //判断row行是否存在st--en的连续区域,每个颜色==ch
{
    for(int i=st;i<=en;i++)
       if(s[row][i]!=ch && s[row][i]!='*')
           return false;
    return true;
}
void bfs()
{
    memset(v,0,sizeof(v));
    int a[2][10];
    for(int i=0;i<2;i++)
        for(int j=0;j<n;j++)
            a[i][j]=1;
    int num=cal(a);
    v[num]=1;
    add(num,s);
    queue<data> q;
    q.push({num,0});  //初始化队列
    while(!q.empty())
    {
        data now=q.front();
        q.pop();
        if(now.step>ans) continue;  //如果超过了预先设定的深度,不往下继续搜索了
        if(now.n==0)  //如果找到了解,直接跳出循环
        {
            ans=now.step;
            return;
        }
        /*先处理第0行*/
        int i=0;
        while(i<n)
        {
            /*得到这个状态的具体字符数组*/
            char ch[2][10];
            for(int i=0;i<2;i++)
                for(int j=0;j<n;j++)
                    ch[i][j]=hash[now.n][i][j];
            int st=i;
            while(ch[0][i]=='*' && i<n) i++;
            if(i>=n) break;  //如果第一行已经搜索完毕了,不找第一行了
            int x1=find(ch,0,i);  //找一个连续相同的序列
            bool fg=findchar(ch,1,ch[0][x1],st,x1);/*判断是不是有一个宽度为2的矩形区域*/
            if(fg)  //如果找到了
            {
                for(int k=0;k<2;k++)
                    for(int kk=st;kk<=x1;kk++)
                        ch[k][kk]='*';
                for(int k=0;k<2;k++)
                    for(int kk=0;kk<n;kk++)
                        if(ch[k][kk]=='*') a[k][kk]=0;
                        else a[k][kk]=1;
                int num=cal(a);
                if(!v[num])
                {
                    v[num]=1;
                    add(num,ch);
                    q.push({num,now.step+1});
                }
            }
            else  //如果没有找到
            {
                for(int k=i;k<=x1;k++)
                    ch[0][k]='*';
                for(int k=0;k<2;k++)
                    for(int kk=0;kk<n;kk++)
                        if(ch[k][kk]=='*') a[k][kk]=0;
                        else a[k][kk]=1;
                int num=cal(a);
                if(!v[num])
                {
                    v[num]=1;
                    add(num,ch);
                    q.push({num,now.step+1});
                }
            }
            i=x1+1;
        }
        /*处理第1行*/
        i=0;
        while(i<n)
        {
            /*得到这个状态的具体字符数组*/
            char ch[2][10];
            for(int i=0;i<2;i++)
                for(int j=0;j<n;j++)
                    ch[i][j]=hash[now.n][i][j];
            int st=i;
            while(ch[1][i]=='*' && i<n) i++;
            if(i>=n) break;  //如果第一行已经搜索完毕了,不找第一行了
            int x1=find(ch,1,i);  //找一个连续相同的序列
            bool fg=findchar(ch,0,ch[1][x1],st,x1);/*判断是不是有一个宽度为2的矩形区域*/
            if(fg)  //如果找到了
            {

                for(int k=0;k<2;k++)
                    for(int kk=st;kk<=x1;kk++)
                        ch[k][kk]='*';
                for(int k=0;k<2;k++)
                    for(int kk=0;kk<n;kk++)
                        if(ch[k][kk]=='*') a[k][kk]=0;
                        else a[k][kk]=1;
                int num=cal(a);
                if(!v[num])
                {
                    v[num]=1;
                    add(num,ch);
                    q.push({num,now.step+1});
                }
            }
            else  //如果没有找到
            {
                for(int k=i;k<=x1;k++)
                    ch[1][k]='*';
                for(int k=0;k<2;k++)
                    for(int kk=0;kk<n;kk++)
                        if(ch[k][kk]=='*') a[k][kk]=0;
                        else a[k][kk]=1;
                int num=cal(a);
                if(!v[num])
                {
                    v[num]=1;
                    add(num,ch);
                    q.push({num,now.step+1});
                }
            }
            i=x1+1;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        memset(s,0,sizeof(s));
        scanf("%d",&n);
        if(n==0)
        {
            printf("Case #%d: %d\n",ca,0);
            continue;
        }
        scanf("%s%s",&s[0],&s[1]);
        ans=16;
        bfs();
        printf("Case #%d: %d\n",ca,ans);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值