解题报告:HDU 4090 GemAnd Prince 搜索



题意:
消消乐,给定一个n*m的多个颜色的砖块矩阵,你可以选择相连的相同颜色的砖块数目大于等于3个的消去,每次消去x个砖块得到的分数是x*x,每次消去后矩阵会变化,上面的浮空的砖块会掉下来,右边的隔开的砖块会整体向左靠,详细变化方式见题目给的说明,现在问你能得到的最大分数。

思路:
题目第一感觉就是一道不那么好写的搜索,仔细分析了一下好像也没有其他做法,写的时候注意下消去后的新矩阵的变化,加上常用的优化,若当前矩阵能得到的最大值小于已经有的最大答案,就停止继续遍历。

代码:
#include<bits/stdc++.h>

const int X[8]={-1,-1,-1,0,0,1,1,1};
const int Y[8]={-1,0,1,-1,1,-1,0,1};
using namespace std;

int n,m,k,ans;

struct node{
    int A[8][8];
};
struct point{
    int x,y,num;
    point(){};
    point(int _x,int _y,int _num=0){
        x = _x;y = _y; num = _num;
    }
};

bool vis[8][8];

int get(node &tt,int x,int y,int k){
    vis[x][y]=true;
    queue<point>Q;
    int res = 1;
    Q.push(point(x,y));
    while(!Q.empty()){
        point t = Q.front();
        Q.pop();
        for(int i=0,a,b;i<8;i++){
            a = t.x+X[i];
            b = t.y+Y[i];
            if(a>=0&&a<n&&b>=0&&b<m&&tt.A[a][b]==tt.A[x][y]&&!vis[a][b]){
                vis[a][b]=true;
                tt.A[a][b]=k;
                Q.push(point(a,b));
                res++;
            }
        }
    }
    tt.A[x][y]=k;
    return res;
}

void oper(node &M){
    for(int j=0;j<m;j++){
        for(int s=n-2,e=n-1;e&&s>=0;e--){
            if(!M.A[e][j]){s = min(s,e-1);
                while(s>=0&&!M.A[s][j])s--;
                if(s>=0){
                    M.A[e][j]=M.A[s][j];
                    M.A[s][j]=0;
                }
            }
        }
    }
    for(int j=0,jj=0;j<m-1;j++){
        if(!M.A[n-1][j]){
            jj = max(jj,j+1);
            while(jj<m&&!M.A[n-1][jj])jj++;
            if(jj<m){
                for(int i=0;i<n;i++){
                    M.A[i][j]=M.A[i][jj];
                    M.A[i][jj]=0;
                }
            }
        }
    }
}

int num[10];
bool check(node& M,int sum){
    memset(num,0,sizeof(num));
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            num[M.A[i][j]]++;
        }
    }
    for(int i=1;i<=k;i++){
        if(num[i]>2)sum+=num[i]*num[i];
    }return sum<=ans;
}

void dfs(node &M,int sum=0){
    ans = max(sum,ans);
    if(check(M,sum))return ;
    queue<point>Q;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(M.A[i][j]&&!vis[i][j]){
                int cnt = get(M,i,j,M.A[i][j]);
                if(cnt>=3)Q.push(point(i,j,cnt));
            }
        }
    }
    while(!Q.empty()){memset(vis,0,sizeof(vis));
        point t = Q.front();Q.pop();
        if(t.num<3)continue;
        node nx = M;
        int cnt = get(nx,t.x,t.y,0);
        oper(nx);
        dfs(nx,sum+cnt*cnt);
    }
}

int main(){
    while(scanf("%d%d%d",&n,&m,&k)==3){
        node t;ans = 0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                scanf("%d",&t.A[i][j]);
            }
        }
        dfs(t);
        printf("%d\n",ans);
    }return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值