UCF Local Programming Contest 2015 H. Reach for the Stars

一看就是搜索或者状压。

但状压不好搞。

我们考虑搜索。

由于涂一个点,会涂十字

直接枚举所有点是否涂(做为中心点)的复杂度是2^81

但其实一个点为中心是否涂 只用判断7*7个,即复杂度压缩到2^49(只能在边界内涂,中心点不能是边界)

仔细观察发现,边界的点只能由次一层边界为中心点涂得。

即:x==2,y==2,x==r-1,y==c-1这些行列需要涂就必须涂,否则就不涂。

这样复杂度缩小为 2^25。是可以接受的复杂度了

然后就是降常数。

即加上最优性剪枝,可行性剪枝,就能过了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)]  //m是矩阵的列数
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
char s[20][20];

int ans,r,c;

void dfs(int x,int y,int step,int ret)//x,y 为中心是否涂,已经涂了step步  还剩ret没涂
{
	if(ret==0){
		ans=min(ans,step);return ;
	} 
	if((ret-1)/5+1+step>=ans)return ;//最优性剪枝
	if(x<=1||x>=r||y<=1||y>=c)return ;//边界 
	char tp[7];
	tp[0]=s[x][y];
	tp[1]=s[x+1][y];tp[2]=s[x][y+1];
	tp[3]=s[x-1][y];tp[4]=s[x][y-1];
	int nm=0;//涂了x,y可是使得多少还没变黑的格子变黑 
	bool f=true;//这个点是否可涂 
	for(int i=0;i<=4;i++)
	{
		if(tp[i]=='#')nm++;
		if(tp[i]=='.')f=false;
	}
	if(f&&nm)//有必要涂才涂 
	{
		s[x][y]=s[x+1][y]=s[x][y+1]=s[x-1][y]=s[x][y-1]='@';
		if(y+1<c)dfs(x,y+1,step+1,ret-nm);
		else dfs(x+1,2,step+1,ret-nm);
		s[x][y]=tp[0];
		s[x+1][y]=tp[1];s[x][y+1]=tp[2];
		s[x-1][y]=tp[3];s[x][y-1]=tp[4];	
		if(x==2||y==2||x==r-1||y==c-1)return;//周围一圈如果需要涂的话 必须涂   否则后面涂不到 
	}
	//这一格不涂 
	if(y+1<c)dfs(x,y+1,step,ret);
	else dfs(x+1,2,step,ret);
	return ;
}
int main()
{
  	int t;
  	cin>>t;
  	for(int ca=1;ca<=t;ca++)
  	{
  		scanf("%d%d",&r,&c);
  		for(int i=1;i<=r;i++)
  		scanf("%s",s[i]+1);
  		int cnt=0;ans=2e9;
  		for(int i=1;i<=r;i++)
  		for(int j=1;j<=c;j++)
  			if(s[i][j]=='#')cnt++;
		dfs(2,2,0,cnt);
  		if(s[1][1]=='#'||s[r][c]=='#'||s[r][1]=='#'||s[1][c]=='#'||ans==2e9)
  		{
  			printf("Image #%d: impossible\n",ca);
  			puts("");
  			continue;
		}
  		printf("Image #%d: %d\n",ca,ans);
  		puts("");
	}
	return 0;
}

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值