NOIP2016模拟 游戏 搜索

这里写图片描述
来源:重庆一中


这道题其实显然是搜索,只不过我看到20*20的数据范围觉得搜索不稳,乱想了比较久,最后只交了个非常暴力的搜索,而且爆零了。搜索是弱项,还需好好加强。

20*20,理论上来说有 2400 种可能,那么要想搜得好,就看怎么剪枝了。数据范围这么大,怎样剪枝比较好呢?事实上并不需要多好的剪枝。题目中说“保证只有唯一解”,那么说明仅仅按这个游戏的规则进行剪枝就能剪掉很多。既然答案唯一,那么搜到了一个答案就不搜了。

所以其实是跑得飞快的。

#include<stdio.h>

int M,N,Black,row[25][25],col[25][25],Tr[25],Tc[25];
//Tr记录某一行的黑色块总数,Tc记录某一列的黑色块总数
int Map[25][25];

bool cr(int x,int r)//检查第x行0~r位置是否合法
{
    int i,tot=0,Now=1,tmp=0;

    for(i=0;i<=r;i++)
    {
        if(Map[x][i])
        {
            tmp++;tot++;
            if(tmp>row[x][Now])return false;
        }
        else if(tmp)
        {
            if(tmp!=row[x][Now])return false;
            tmp=0;Now++;
        }
    }
    if(tot+M-r-1<Tr[x])return false;//剩下的位置全部填满也不行,不合法
    if(tot>Tr[x])return false;//多了,不合法
    return true;
}

bool cc(int x,int r)//检查第x列0~r位置是否合法,基本上和cr函数一样
{
    int i,tot=0,Now=1,tmp=0;

    for(i=0;i<=r;i++)
    {
        if(Map[i][x])
        {
            tmp++;tot++;
            if(tmp>col[x][Now])return false;
        }
        else if(tmp)
        {
            if(tmp!=col[x][Now])return false;
            tmp=0;Now++;
        }
    }
    if(tot+N-r-1<Tc[x])return false;
    if(tot>Tc[x])return false;
    return true;
}
bool Find;
void DFS(int cur,int rem)//cur:当前讨论到的格子的编号,从0开始;rem:剩下的黑色块的数量
{
    if(Find)return;

    int i,x,y;

    if(cur)
    {
        x=(cur-1)/M;y=(cur-1)%M;
        if(!cr(x,y))return;
        for(i=0;i<=y;i++)if(!cc(i,x))return;
    }

    if(cur==N*M)
    {
        int i,j;
        for(i=0;i<N;i++,putchar('\n'))
        for(j=0;j<M;j++)
        {
            if(Map[i][j])putchar('#'),putchar('#');
            else putchar(' '),putchar(' ');
        }
        Find=true;
        return;
    }

    if(rem==-1)return;

    x=cur/M;y=cur%M;
    Map[x][y]=1;
    DFS(cur+1,rem-1);
    Map[x][y]=0;
    DFS(cur+1,rem);
}

int main()
{
    int i,x;

    scanf("%d%d",&M,&N);

    for(i=0;i<M;i++)
    {
        scanf("%d",&x);
        while(x)
        {
            col[i][++col[i][0]]=x;Black+=x;Tc[i]+=x;
            scanf("%d",&x);
        }
    }

    for(i=0;i<N;i++)
    {
        scanf("%d",&x);
        while(x)
        {
            row[i][++row[i][0]]=x;Tr[i]+=x;
            scanf("%d",&x);
        }
    }

    DFS(0,Black);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值