POJ 2965【The Pilots Brothers' refrigerator】

17 篇文章 0 订阅
13 篇文章 0 订阅

题目链接

思路:

  • 因为刚做完Flip Game嘛,很快就敲出了第一版代码~

  • 可是TLE了,又没有别的办法,只能尝试把判断符号 ‘+’‘-’ 改成判断 bool 这样子…也过了…

  • 然后WA…先贴出WA部分,你可以试着想想为什么。

//这里是dfs()中的第一部分:停搜条件
	if(flag)
		return ;
	if(row == 5)
		return ;
	if(deep == step){
  		flag = judge();
		return ;
 	}
  • 答案是:第二和第三,这两个判断条件写反了。
  • 明白了吗?设想一种情况,这种情况下正解的最后一步是将 mp[4][4] 取反。因为翻转 mp[4][4] 后进入的是对下一个格子(mp[5][1])的深搜,这时候若先判断本格是否合法,那么就没法改变flag了。答案被跳过,最后程序运行结果是一行孤零零的数字17
  • 这两个坑填平,就AC啦。

然后去网上看到了更好的解法,也不难理解,在此复述一遍:

  • 首先要明确一个结论:以 mp[i][j] 为例,若我们对所有属于第 i 行或第 j 列的七个格子都做一次本题所述的操作(即一共进行七七四十九单格取反),则最后只有 mp[i][j] 这一个格子被取反。
  • 其次,对任何一个格子,在一局游戏中只有两种可能:不取反、取反。
  • 并且要知道,在整局游戏的尺度下,对两次不同的题述操作来说,它们的操作时间和顺序对结果没有任何影响
  • 如此,我们就可以对原棋盘每个 ‘+’ 所属的家族中的所有家族成员(其实就是以它为中心的七个格子啦)操作数加一,并且使用第二条结论,把操作数加一定义为对它的 reverse 取反。
  • 最后,所有需要reverse的格子数量就是最小操作数,把他们所在的位置输出就是操作的位置啦。

代码:

  • TLE版本
#include <iostream>
#include <algorithm>

using namespace std;

char mp[6][6];
bool flag = false;
int movement[16][2];
int t=0;
int step;

void input(){
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			cin>>mp[i][j];
	return ;
}

bool judge(){
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(mp[i][j] == '+')
				return false;
	return true;
}

void flip(int row,int col){
	if(mp[row][col] == '-')
		mp[row][col] = '+';
	else
		mp[row][col] = '-';
		
	for(int i=1;i<=4;i++){
		if(mp[i][col] == '-')
			mp[i][col] = '+';
		else
			mp[i][col] = '-';
	}
	for(int j=1;j<=4;j++){
		if(mp[row][j] == '-')
			mp[row][j] = '+';
		else
			mp[row][j] = '-'; 
	} 
	return ;
}

void dfs(int row,int col,int deep){
	if(flag)
		return ;
	if(deep == step){
		flag = judge();//first
		return ;
	}//注意这两个函数不能写反,因为有可能是翻完mp[4][4],才是正解
	//如果得到正解后,先判断下一格是否越界,flag就没机会改变 
	if(row == 5)//second
		return ;
	
	flip(row,col);
	movement[t][0] = row;
	movement[t][1] = col;
	t++;
	if(col < 4)
		dfs(row , col+1 , deep+1);
	else
		dfs(row+1 , 1   , deep+1);
	if(flag)
		return ;
	flip(row,col);
	t--;
	
	if(col < 4)
		dfs(row , col+1 , deep);
	else
		dfs(row+1 , 1   , deep);
	return ;
}

void output(){
	cout<<step<<endl;
	for(int i=0;i<t;i++)
		cout<<movement[i][0]<<' '<<movement[i][1]<<endl;
	return ;
}

int main(){
	input();
	for(step = 1 ; step <= 16 ; step++){
		dfs(1,1,0);
		if(flag)
			break;
	}
	output();
	return 0;
}
  • 正解版本:648K 469MS
//648K		469MS


#include <iostream>
#include <algorithm>

using namespace std;

bool mp[6][6];
bool flag = false;
int movement[16][2]; 
int t=0;
int step;

void input(){
	char tp;
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++){
			cin>>tp;
			if(tp == '-')
				mp[i][j] = true;
			else
				mp[i][j] = false; 
		}
	return ;
}

bool judge(){
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(!mp[i][j])
				return false;
	return true;
}

void flip(int row,int col){
	mp[row][col] = !mp[row][col];
		
	for(int i=1;i<=4;i++)
		mp[i][col] = !mp[i][col];
	for(int j=1;j<=4;j++)
		mp[row][j] = !mp[row][j];
	
	return ;
}

void dfs(int row,int col,int deep){
	if(flag)
		return ;
	if(deep == step){
		flag = judge();//first
		return ;
	}//注意这两个函数不能写反,因为有可能是翻完mp[4][4],才是正解
	//如果得到正解后,先判断下一格是否越界,flag就没机会改变 
	if(row == 5)//second
		return ;
	
	flip(row,col);
	movement[t][0] = row;
	movement[t][1] = col;
	t++;
	if(col < 4)
		dfs(row , col+1 , deep+1);
	else
		dfs(row+1 , 1   , deep+1);
	if(flag)
		return ;
	flip(row,col);
	t--;
	
	if(col < 4)
		dfs(row , col+1 , deep);
	else
		dfs(row+1 , 1   , deep);
	return ;
}

void output(){
	cout<<step<<endl;
	for(int i=0;i<t;i++)
		cout<<movement[i][0]<<' '<<movement[i][1]<<endl;
	return ;
}

int main(){
	input();
	for(step = 1 ; step <= 16 ; step++){
		dfs(1,1,0);
		if(flag)
			break;
	}
	output();
	return 0;
}
  • 锦囊版本:640K 125MS
//640K		125MS


#include <iostream>
#include <cstring>

using namespace std;

bool mp[6][6];
bool reverse[6][6];
int ans = 0;

void input(){
	memset(mp,0,sizeof(mp));
	char tp;
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++){
			cin>>tp;
			if(tp == '-')
				mp[i][j] = true;
		}
	return ; 
}

void reverseone(int x,int y){
	reverse[x][y] = !reverse[x][y];
	for(int i=1;i<=4;i++)
		reverse[i][y] = !reverse[i][y];
	for(int j=1;j<=4;j++)
		reverse[x][j] = !reverse[x][j];
	return ;
}

void output(){
	cout<<ans<<endl;
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(reverse[i][j])
				cout<<i<<' '<<j<<endl;
	return ;
}

int main(){
	input();
	memset(reverse,0,sizeof(reverse));
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(!mp[i][j])
				reverseone(i,j);
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(reverse[i][j]) ans++; 
	output();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值