ACM日记之枚举法+DFS

今天刷了两个拖了好几天的题,写完发现好简单,网络上有好几种方法,枚举,BFS...我只会暴力枚举+BFS(最简单的)(/ □ \)。

HDU 1753    Flip Game

 

题目的大概意思就是给一个棋盘,例如

bwbw 
bwww 
wwwb 

wwwb     (b指black,w指white五五开)

可以翻转一个棋子,而且棋子的周围(上下左右)都会翻转,问至少翻转多少次可以将棋盘变成纯色(纯黑或者纯白)

思路:因为每个棋子翻转0次和翻转2次,即翻转偶数次是一样的结果。奇数同理。

棋盘为4✖4,所以有16个棋子,我们可以枚举只翻转棋子的数目0~16.

一共会枚举.

代码如下:

#include<cstdio>
#include <iostream>
using namespace std;
#include<cstring>
int chess[16+5][16+5];
bool flag=0;
int step;			//枚举步数,从0~16步 
int rf[5]={-1,0,1,0,0};	//上,右,下,左,自身 			行 
int cf[5] ={0,1,0,-1,0}	;//上,右,下,左,自身 			列 
bool isover()
{
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
		if(chess[i][j]!=chess[1][1])
		return false;
	return true;
}
void fz(int r,int c)
{
	for(int i=0;i<=4;i++)
	{
		chess[r+rf[i]][c+cf[i]]=!chess[r+rf[i]][c+cf[i]];
	}
}
void bfs(int r,int c,int deep)
{
	if(deep==step)
	{
		flag=isover();
		return ; 
	}
	 if(flag || r==5)  		//flag==1已经完成,row==5已经出棋盘 
    {  
        return;  
    }  
	fz(r,c);		//翻转 
	if(c<4)
	{
		bfs(r,c+1,deep+1);
	}
	else
	{
		bfs(r+1,1,deep+1);
	}
	fz(r,c);			//假如第一个不翻转,就将第一个翻转回原样 
	if(c<4)
	{
		bfs(r,c+1,deep);
	}
	else
	{
		bfs(r+1,1,deep);
	}
	return;
	
}
int main()
{
	char ch;
	memset(chess,0,sizeof(chess));
	for(int i=1;i<=4;i++)
	{
		for(int j=1;j<=4;j++)
		{
			scanf("%c",&ch);
			if(ch=='b')
			chess[i][j]=1;
		}
		getchar();
	}

	for(int i=0;i<=16;i++)
	{
		step=i;
		bfs(1,1,0);
		if(flag) 
		break;
	}
	if(flag) 
	printf("%d\n",step);
	else
	printf("Impossible\n");
	return 0;
}

HDU  2965

这题和上面的翻转棋子类似,只是翻转冰箱的门把手,一共16个门把手,也是可以翻转一次,但是这次如果翻转第i行,第j列的门把手,整个行和整个列的门把手都会被翻转。只不过这次不仅要输出最小步数,还要输出每步翻转的地方是那里。

思路:我们可以类似上面的方法枚举看,只要在改变判flag 的条件,然后在翻转的时候用一个数组记录一下i,j行列就好了。代码和上面很像。

代码如下:

#include<cstdio>
#include<cstring>
#define maxn 1000000
int door[4+5][4+5];		
bool flag=false;
int num=0,step=0;		//num用于记录开关的过程,两个为一个位置 ,step用于枚举步数 
int s[maxn]; 		//记录开关门的过程 
bool isover()
{
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
		{
			if(door[i][j]==1)
			return false;
		 } 
	return true;
} 
void fz(int r,int c,int x)			//r是行,c是列 
{
	x+=1;		//第一步时x也就是deep是等于step-1; 
	s[x*2-1]=r;
	s[x*2]=c;
	for(int i=1;i<=4;i++)
	{
		door[r][i]=!door[r][i];
		door[i][c]=!door[i][c];
	}
	door[r][c]=!door[r][c];
}
void dfs(int r,int c,int deep)
{
	if(deep==step)
	{
		flag=isover();
		return ;
	}
	if(flag||r>=5)
	{
		return;
	}
	fz(r,c,deep);
	if(c<4)
		dfs(r,c+1,deep+1);
	else
		dfs(r+1,1,deep+1);
	fz(r,c,deep);
	if(c<4)
		dfs(r,c+1,deep);
	else
		dfs(r+1,1,deep);
		return ;
	
	
}
int main()
{
	char ch;
	memset(door,0,sizeof(door));
	for(int i=1;i<=4;i++)
		{
			for(int j=1;j<=4;j++)
			{
				scanf("%c",&ch);
				if(ch=='+')				//+代表关闭,1代表关闭 
				door[i][j]=1;
			}
			getchar();
		}
		/*for(int i=1;i<=4;i++)
		{
			for(int j=1;j<=4;j++)
			{
				printf("%d ",door[i][j]);
			}
			printf("\n");
		}*/
	for(int i=0;i<=16;i++)
	{
		step=i;
		dfs(1,1,0);
		if(flag)
		break;	
	} 
	if(flag)
	{
		printf("%d\n",step);
		for(int i=1;i<=step*2;i++)
		{
			if(i&1==1)			//为奇数 
			printf("%d ",s[i]);
			else
			printf("%d\n",s[i]);
		} 
	}
	else
	printf("impossible\n");
	return 0;
	
}

emmm蓝桥杯,校赛,省赛在即,希望自己能加油多刷一点题!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值