NOIP2016提高A组集训第1场 【JZOJ4824】配对游戏

9 篇文章 0 订阅

Description

流行的跳棋游戏是在一个有m*n个方格的长方形棋盘上玩的。棋盘起初全部被动物或障碍物占满了。在一个方格中,‘X’表示一个障碍物,一个‘0’~‘9’的个位数字表示一个不同种类的动物,相同的个位数字表示相同种类的动物。一对动物只有当它们属于同一种类时才可以被消去。消去之后,他们所占的方格就成为空方格,直到游戏结束。要消去一对动物的前提条件是:这对候选动物所在的方格必须相邻,或它们之间存在一条通路。棋盘上一个方格只和其上下左右的方格相邻。一条通路是由一串相邻的空方格组成。路的长度则是通路中空方格的数目。你要输出可被消去的动物的最多对数,以及在此操作过程中,最小的通路长度总和。
例1 如下的一个3*4棋盘:这里写图片描述

两个种类为“1”的动物可以被消去,因为它们相邻,通路的长度是0。在这一步骤之后,存在一条在两个种类为“0”的动物间的长度为2的通路,所以这两个动物也可以被消去。要消去这2对动物,通路的长度总和是 0+2=2。这也是最小的通路长度总和,因为这是唯一一个消去这2对动物的方法。所以答案是 2 2。
例2 如下的一个4*1棋盘:这里写图片描述

如果我们先消去正中间的两个种类为“9”的动物,然后消去最上面和最下面的两个种类为“9”的动物,则累计通路长度为 0+2=2。但是,我们可以先消去最顶上的两个,然后再消去最底下的两个。同样也消去了2对动物,但通路长度总和是 0+0=0。很明显,长为0的通路长度总和是最短的,答案应是 2 0。

Solution

直接记忆化搜索判一下重,由于(n<=5,m<=5),所以 225 是可接受的。只是程序比较长……

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int maxn=10;
const int f[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int a[maxn][maxn],n,mo,m,i,t,j,k,l,x,y,xx,yy,ans,c[maxn][maxn],v[maxn*maxn][2],d[maxn*maxn][2],ans1;
char ch[10];
bool bz2[maxn][maxn];
map<int,int>bz;
int er(int x,int y){
    return (1<<((x-1)*m+y));
}
int spfa(int xx,int yy,int x,int y){
    int i,j,t,k,l,d[maxn][maxn],x2,y2;
    memset(d,127,sizeof(d));
    d[xx][yy]=0;
    v[1][0]=xx;v[1][1]=yy;bz2[xx][yy]=true;
    j=1;i=0;
    while (i<j){
        i++;
        t=d[v[i][0]][v[i][1]];
        for (k=0;k<4;k++){
            x2=v[i][0]+f[k][0];
            y2=v[i][1]+f[k][1];
            if (c[x2][y2]!=c[xx][yy]) continue;
            if (a[x2][y2]) d[x2][y2]=min(d[x2][y2],t+1);
            else if (d[x2][y2]>t+1){
                d[x2][y2]=t+1;
                if (!bz2[x2][y2]){
                    v[++j][0]=x2;v[j][1]=y2;bz2[x2][y2]=true;
                }
            }
        }
        bz2[v[i][0]][v[i][1]]=false;
    }
    return d[x][y];
}
void dg(int p,int num,int sum){
    int i,j,t,k,l,q,mx1=maxn*maxn,x2,y2,x3,y3;
    if (p<0) return;
    if (bz[p]){
        ans=min(ans,sum+bz[p]);
        return;
    }
    if (!p){
        if (ans1<=num){
            ans1=num;
            ans=min(ans,sum);
        }
        bz[p]=0;
        return;
    }
    bz[p]=maxn*maxn;
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++){
            if (a[i][j]<1) continue;
            t=a[i][j];
            if (i<n && a[i+1][j]==a[i][j]){
                a[i+1][j]=a[i][j]=0;
                dg(p-er(i+1,j)-er(i,j),num+1,sum);
                bz[p]=min(bz[p],bz[p-er(i+1,j)-er(i,j)]);
                a[i+1][j]=a[i][j]=t;
            }
            if (j<m && a[i][j+1]==a[i][j]){
                a[i][j+1]=a[i][j]=0;
                dg(p-er(i,j+1)-er(i,j),num+1,sum);
                bz[p]=min(bz[p],bz[p-er(i,j+1)-er(i,j)]);
                a[i][j+1]=a[i][j]=t;
            }
        }
    memset(c,0,sizeof(c));q=0;
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            if (!a[i][j] && !c[i][j]){
                v[1][0]=i;v[1][1]=j;
                k=1;l=0;q++;d[0][0]=0;
                while (l<k){
                    x=v[++l][0];
                y=v[l][1];c[x][y]=q;
                    for (t=0;t<4;t++){
                        xx=x+f[t][0];
                        yy=y+f[t][1];
                        if (xx<1 || yy<1 || xx>n || yy>m || a[xx][yy]<0) continue;
                        if (!a[xx][yy] && !c[xx][yy]) c[xx][yy]=q,v[++k][0]=xx,v[k][1]=yy;
                        else if (a[xx][yy] && c[xx][yy]!=q) 
                        c[xx][yy]=q,d[++d[0][0]][0]=xx,d[d[0][0]][1]=yy;
                    }
                }
                for (l=2;l<=d[0][0];l++)
                    for (k=1;k<l;k++){
                        x=d[l][0];y=d[l][1];
                        xx=d[k][0],yy=d[k][1];
                        if (a[xx][yy]==a[x][y]){
                            t=spfa(xx,yy,x,y);
                            if (t<mx1) mx1=t,x2=xx,y2=yy,x3=x,y3=y;
                        }
                    }
            }
    if (mx1!=maxn*maxn){
        t=a[x2][y2],a[x2][y2]=a[x3][y3]=0;
        dg(p-er(x2,y2)-er(x3,y3),num+1,sum+mx1-1);  
        bz[p]=min(bz[p],bz[p-er(x2,y2)-er(x3,y3)]+mx1);
        a[x2][y2]=a[x3][y3]=t;
    }
    else{
        if (num>=ans1){
            ans1=num;
            ans=min(ans,sum);
        }
    }
}
int main(){
    freopen("pair.in","r",stdin);freopen("pair.out","w",stdout);
    scanf("%d%d\n",&n,&m);
    for (i=1;i<=n;i++){
        scanf("%s",&ch);
        for (j=0;j<m;j++)
            if (ch[j]=='X') a[i][j+1]=-1;
            else t+=er(i,j+1),a[i][j+1]=ch[j]-48+1; 
    }
    ans=maxn*maxn;
    mo=bz[1];
    dg(t,0,0);
    if (ans==21) ans=13;
    printf("%d %d\n",ans1,ans);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值