ZOJ 2977

乍一看蛮恶心的不知道怎么搜索,但是后来一想其实只要枚举第一行的状态,也就是遍历第一行的每个点(按与不按),然后每一行更具上一行来选择按与不按;

即如果map[i-1][j]=='X'那么(i,j)一定要按;

时间复杂度大概就在2^16*n^2;是可以接受的;具体的注释见代码;

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#define INF 1000000
using namespace std;
char map[20][20];//输入;
char cop[20][20];//用于还原map数组的状态;
int n,m;
int ans;
int move[5][2]={{1,0},{-1,0},{0,1},{0,-1},{0,0}};//用于把自己本身以及相邻的四个点反向;
int yes;//用于判断是否可以全部变为白色;
int minans;//输出最小的部数;
int k;//在work函数运行过之后还原ans的值;
void change(int x,int y)//次函数用于改变自己以及相邻的四个点
{
    for(int i=0;i<5;i++)
    {
        int nx=x+move[i][0];
        int ny=y+move[i][1];
        if(0<=nx&&nx<n&&0<=ny&&ny<m)
        {
            if(map[nx][ny]=='X')
            {
                map[nx][ny]='.';
            }
            else
            {
                map[nx][ny]='X';
            }
        }
    }
}
void work()
{
    k=ans;
    for(int i=0;i<n;i++)//记录之前map的状态 方便之后的还原;
    {
       for(int j=0;j<m;j++)
       {
           cop[i][j]=map[i][j];
       }
    }
    int ju=0;
    for(int i=1;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(map[i-1][j]=='X')
            {
                change(i,j);
                ans++;
            }
        }
    }
   for(int j=0;j<m;j++)//判断最后一行是不是都班委白色的了;
   {
       if(map[n-1][j]=='X')
       {
           ju=1;
           break;
       }
   }
   if(ju==0)
   {
       yes=1;
   }
   else
   {
       yes=0;
   }
   for(int i=0;i<n;i++)//把map还原到之前的状态;
   {
       for(int j=0;j<m;j++)
       {
           map[i][j]=cop[i][j];
       }
   }
   return;
}
void dfs(int y)//用于枚举第一行的状态(即为按与部按)最多也就是2的16次方;
{
   if(y==m)//dfs的结束条件;
   {
       work();
       if(yes==1)
       {
            minans=min(minans,ans);// 如果可以全部变为白色就比较minans与ans的大小;
       }
       ans=k;//还原ans的值;
       return;
   }
   //下面就是两种情况——按与不按;
    change(0,y);
    ans++;
    dfs(y+1);
    ans--;
    change(0,y);
    dfs(y+1);
    return;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        for(int i=0;i<n;i++) scanf("%s",map[i]);
        ans=0;
        yes=0;
        minans=INF;
        dfs(0);
        if(minans==INF)
        {
            printf("Damaged billboard.\n");
        }
        else
        {
            printf("You have to tap %d tiles.\n",minans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值