POJ1753 Flip Game(AC)

Flip Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 46594 Accepted: 19948

Description

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules: 
  1. Choose any one of the 16 pieces. 
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

Consider the following position as an example: 

bwbw 
wwww 
bbwb 
bwwb 
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become: 

bwbw 
bwww 
wwwb 
wwwb 
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal. 

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4

Source


//20170902
//多少步才能全白或者全黑,最小步
//DFS的过程是将所有过程都遍历下
//此题第一遍是所有棋子都不动
//到最后一个棋子的不动状态,然后就到最后一个棋子需要翻的状态,函数返回,再到倒数第2个棋子需要翻的状态,然后是最后一个棋子翻和不翻的两个状态再走一遍
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#define MAXN 5

char matrix[MAXN][MAXN];
int ans = 130000;

int whitenum = 0;
int blacknum = 0;

int dis[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, {0,-1} };

int strcmpp(char* s, char*d)
{	
	while (*s != '\0')
	{
		if (*s != *d) return 0;
		s += 1;
		d += 1;
	}
	return 1;
}

int same()
{
	int i = 0;
	int j = 0;
	int white = 0;
	int black = 0;

	if (strcmpp(matrix[0], "bbbb") && strcmpp(matrix[1], "bbbb") && strcmpp(matrix[2], "bbbb") && (strcmpp(matrix[3], "bbbb")))
	{
		return 1;
	}
	else if(strcmpp(matrix[0], "wwww") && strcmpp(matrix[1], "wwww") && strcmpp(matrix[2], "wwww") && (strcmpp(matrix[3], "wwww")))
	{
		return 1;
	}
	else
	{
		return 0;
	}					


	return 0;
}

void reverse(int x, int y)
{
	int i = 0;
	int j = 0;
	int tmpx = 0;
	int tmpy = 0;
	//注意中心点也要变的
	if ('b' == matrix[x][y])
	{
		matrix[x][y] = 'w';
	}
	else
	{
		matrix[x][y] = 'b';
	}

	for (i = 0; i < 4;i++)
	{
		tmpx = x + dis[i][0];
		tmpy = y + dis[i][1];
		if ((tmpx<0) || (tmpx >= 4) || (tmpy<0) || (tmpy>=4)) continue;
		if ('b' == matrix[tmpx][tmpy])
		{
			matrix[tmpx][tmpy] = 'w';
		}
		else
		{
			matrix[tmpx][tmpy] = 'b';
		}
	}
	return;
}

void dfs(int x, int y, int step)
{
	int i = 0;
	if ((x<0) ||(x>=4)||(y<0)) return;
	if (ans<=step) return; //进来的步数已经比现在大了,那就不需要再比较了

	if (1 == same())
	{
		if (ans>step)
		{
			ans = step;
		}
		return;
	}

	if (y >= 4)
	{
		x += 1;//换行
		y = 0;//这个不能漏
	}

	//每个点都可以翻或不翻
	for (i = 1; i <= 2;i++)
	{
		//(x,y)点不翻,直接到下一个点
		if (1 == i)
		{
			dfs(x, y + 1, step);
		}
		else
		{
			reverse(x, y);
			dfs(x, y + 1, step + 1);
			reverse(x, y);
		}
	}

	return;
}

int main()
{
	int i = 0;
	int j = 0;
	int step = 0;
	freopen("input.txt","r",stdin);
	for (i = 0; i < 4;i++)
	{
		scanf("%s",matrix[i]);
		for (j = 0; j < 4;j++)
		{
			if ('b' == matrix[i][j])
			{
				blacknum += 1;
			}
			else
			{
				whitenum += 1;
			}
		}
	}

	//矩阵这么小,可以用DFS做
	if (1 == same())
	{
		printf("0\n");
	}
	else
	{
		//dfs
		/*for (i = 0; i < 4;i++)
		{
			for (j = 0; j < 4; j++)
			{
				dfs(i,j,);
			}
		}*/

		//不用for循环,因为DFS里面会不断check
		dfs(0, 0, step);


		if (130000 == ans)
		{
			printf("Impossible\n");
		}
		else
		{
			printf("%d\n",ans);
		}
	}

	return 0;
}


 
 
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#define MAXINT 5

char map[MAXINT][MAXINT];
int  visit[MAXINT][MAXINT];
int  ans = 10000;
int shu = 0;

int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
/*ST AC*/

//因为题目中定了是只有4*4的矩阵,所以可以用DFS
//而且我认为每个元素只能当一次中心,否则就没法弄了这道题

/*第一次提交WA 20/100 后来reverse加了中心点也要取反*/
/*第二次提交WA 40/100 然后发现主体代码写的就不太对,找点的时候都是随机找的,而不是从四个方向找,取反是从四个方向取反的
  但是这样改之后发现时间复杂度很高,超时*/

/*每个点要么变要么不变,然后一共16个点,那时间复杂度应该是2^16,但是我写的代码怎么就变成16!(16*15*...*2*1),这个不对的呀,肯定有很多重复的场景存在*/
/*最终的解题方法还是参考的别人的代码的,自己还是要增加主观能动性啊*/
/*第四次提交85/100 没有考虑全黑全白的情况,ans没有重新赋值*/
/*修改后第五次提交95/100 找不到什么具体的原因啊。。。。
  走查代码找到了
  if (3 == x) //如果x搜索到最后一行,则重新开始,然后列增加
	{
		x = -1; //因为后面会给x+1的,如果这边x=0的话,那0行就错过了,这是不对的
		y += 1;
	}
原来写的是x=0*/

void init()
{
	int k = 0;
	int j = 0;
	for (j = 0; j < MAXINT; j++)
	{
		for (k = 0; k < MAXINT; k++)
		{
			map[j][k]   = '\0';
			visit[j][k] = 0;
		}
	}
	ans = 10000;
	shu = 0;
	return;
}

int check()
{
	int i = 0;
	int j = 0;
	int black = 0;
	int white = 0;
	for (i = 0; i < 4;i++)
	{
		for (j = 0; j < 4;j++)
		{
			if ('b' == map[i][j])
			{
				black += 1;
			}
			else
			{
				white += 1;
			}
			if ((0 != black) && (0 != white))
			{
				return 0;
			}
		}
	}
	return 1;
}

void Reverse(int x, int y )
{
	int i = 0;
	if ((x < 0) || (x>3) || (y < 0) || (y>3)) return;
	//注意这个中心值
	if ('b' == map[x][y])
	{
		map[x][y] = 'w';
	}
	else
	{
		map[x][y] = 'b';
	}
	for (i = 0; i < 4;i++)
	{
		int x1 = x + dir[i][0];
		int y1 = y + dir[i][1];
		if ((x1 < 0) || (x1>3) || (y1 < 0) || (y1>3)) continue;
		if ('b' == map[x1][y1])
		{
			map[x1][y1] = 'w';
		}
		else
		{
			map[x1][y1] = 'b';
		}
	}
	return;
}

void dfs(int x, int y, int num) //num表示有多少个已经动过也就是步数
{
	int i = 0;
	int j = 0;
	int k = 0;
	//if ((x < 0) || (x>3) || (y < 0) || (y>3)) return;

	if (4 == y) return;//已经搜到最后一个点了,不再搜索了
	if (3 == x) //如果x搜索到最后一行,则重新开始,然后列增加
	{
		x = -1; //因为后面会给x+1的,如果这边x=0的话,那0行就错过了,这是不对的
		y += 1;
	}


	//重要的剪枝,如果走的步数已经要大于已经存的结果,直接return,后面的搜索无意义
	if (ans <= num)
	{
		return;
	}
	
	if (1 == check()) //check有没有都变成白色或黑色
	{	
		if (ans > num) ans = num;
		return;
	}

	//如果16个已经动过,那只能返回了,如果是全黑或全白前面就判断过了
	if (16 == num)  
	{
		return;
	}

	//这个写的都不对,第2个点不是从四个方向找的,可以随机选点的,这个一定要注意,前2次提交都是不对的
	/*for (i = 0; i < 4;i++)
	{
		int x1 = x + dir[i][0];
		int y1 = y + dir[i][1];
		if ((x1 < 0) || (x1>3) || (y1 < 0) || (y1>3)) continue;
		if (1 == visit[x1][y1]) continue;
		visit[x1][y1] = 1;
		dfs(x1,y1,num+1);
		//回溯
		visit[x1][y1] = 0;
	}*/

	/*这样写不对的原因在于有很多重复的场景存在,导致时间复杂度达到16!*/
	/*for (j = 0; j < 4; j++)
	{
		for (k = 0; k < 4; k++)
		{
			if (1 == visit[j][k]) continue;
			Reverse(j, k);
			visit[j][k] = 1;
			dfs(j, k, num+1); 
			printf("%d,j=%d,k=%d\n",shu++,j,k);
			//回溯
			visit[j][k] = 0;
			Reverse(j, k);
		}
	}*/
	dfs(x+1, y, num); //(x+1,y)不变

	Reverse(x + 1, y);
	dfs(x + 1, y, num+1); //(x+1,y)变
	Reverse(x + 1, y);

	return;
}

int main()
{
	int i = 0;
	int j = 0;
	int k = 0;
	int T = 0;
	freopen("input.txt","r",stdin);
	scanf("%d",&T);
	for (i = 0; i < T;i++)
	{
		init();
		for (j = 0; j < 4;j++)
		{
			scanf("%s",&map[j]);
		}
		//check是否存在已经是全黑或全白的情况
		if (0 == check())
		{
			/*for (j = 0; j < 4; j++)
			{
				for (k = 0; k < 4; k++)
				{
					Reverse(j, k);
					visit[j][k] = 1;
					dfs(j, k, 1); //第一个起点不一定是从0,0开始的,这个要注意的
					//printf("%d\n", shu++);
					//回溯
					visit[j][k] = 0;
					Reverse(j, k);
				}
			}*/
			//visit[0][0] = 1;
			dfs(0, 0, 0); //(0,0)不变
			//visit[0][0] = 0;

			//visit[0][0] = 1;
			Reverse(0, 0);
			dfs(0, 0, 1); //(0,0)变
			//visit[0][0] = 0;
			Reverse(0,0); //这边不回溯应该也没关系,因为也不会再用了,这样可以节省点时间
		}
		else
		{
			ans = 0;//说明有全黑或全白
		}

		if (10000 == ans)
		{
			printf("impossible\n");
		}
		else
		{
			printf("%d\n",ans);
		}
	}
	return 0;
}
 
<pre class="cpp" name="code">#include <stdio.h>
//一共就4*4所以可以用dfs来做
//第一次提交95/100,AC1第一次做的时候也犯过类似的错误
/*
if (y>=4)
{
x = x + 1;
y = 0; //这里写的y=1不对的,我们是从0开始的,哎,哎,这个1,0还是很容易弄错
}
*/
#define MAXINT 10
#define MAX 100000
char map[MAXINT][MAXINT];
int ans = MAX;

int dir[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, {0,-1} };

void init()
{
	int i = 0;
	int j = 0;
	for (i = 0; i < MAXINT; i++)
	{
		for (j = 0; j < MAXINT; j++)
		{
			map[i][j] = '\0';
		}
	}
	ans = MAX;
	return;
}

int check()
{
	int i = 0;
	int j = 0;
	char test = map[0][0];
	for (i = 0; i < 4;i++)
	{
		for (j = 0; j < 4; j++)
		{
			if (test != map[i][j]) return 0;
		}
	}
	return 1;
}

void Revert(int x, int y)
{
	int i = 0;
	if ('b' == map[x][y])
	{
		map[x][y] = 'w';
	}
	else
	{
		map[x][y] = 'b';
	}
	for (i = 0; i < 4;i++)
	{
		int x1 = x + dir[i][0];
		int y1 = y + dir[i][1];
		if ((x1<0) || (x1 >= 4) || (y1<0) || (y1 >= 4)) continue;
		if ('b' == map[x1][y1])
		{
			map[x1][y1] = 'w';
		}
		else
		{
			map[x1][y1] = 'b';
		}
	}
	return;
}

void dfs(int x,int y,int step)
{
	int i = 0;
	if (1 == check())
	{
		if (ans > step)
		{
			ans = step;
		}
		return;
	}

	if (y>=4)
	{
		x = x + 1;
		y = 0; //这里写的y=1不对的,我们是从0开始的,哎,哎,这个1,0还是很容易弄错
	}

	if (x>=4)
	{
		return;
	}

	//这个点有2个选择,反还是不反
	for (i = 1; i <= 2;i++)
	{
		if (1 == i)  //这个点不动
		{
			dfs(x, y + 1, step);
		}
		else //取反
		{
			Revert(x, y);
			dfs(x, y + 1, step + 1);
			//回溯
			Revert(x, y);
		}
	}
	return;
}


int main()
{
	int i = 0;
	int j = 0;
	int k = 0;
	int T = 0;
	freopen("input.txt","r",stdin);
	scanf("%d",&T);
	for (i = 0; i < T;i++)
	{
		init();
		for (j = 0; j < 4;j++)
		{
			scanf("%s",&map[j]);
		}
		dfs(0, 0, 0);
		if (MAX != ans)
		{
			printf("%d\n", ans);
		}
		else
		{
			printf("impossible\n");
		}
	}
	return 0;
}


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值