您的位置:首页 > 其它

csdn英雄会题解之翻纸牌游戏__hdu2209

2014-03-22 15:47 253 查看
题目描述 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌。但是麻烦的是,每当你翻一张纸牌(由正翻到反,或者有反翻到正)时,他左右两张纸牌(最左边和最右边的纸牌,只会影响附近一张)也必须跟着翻动,现在给你一个乱的状态,问你能否把他们整理好,使得每张纸牌都正面朝上,如果可以,最少需要多少次操作。
输入 有多个case,每个case输入一行01符号串(长度不超过20),1表示反面朝上,0表示正面朝上。 输出 对于每组case,如果可以翻,输出最少需要翻动的次数,否则输出NO。

我的做法:

每张扑克牌有主动翻和主动不翻(主动翻两次相等于主动不翻)两种情况,那么总共有2^n方种情况,如果这2^n方中情况中仍不能找到使其都为正面朝上,那么肯定就找不到了,因为再继续找下去,肯定会出现某个主动翻两次,又转换为2^n方内的情况了。采用DFS搜索所有情况:

代码为:

#include<iostream>
#include<iterator>
#include<string>
#include<stdio.h> 
#include<string.h> 
const int maxn=20;
bool flag[maxn];//是否主动翻动过
int times=INT_MAX;

bool isOk(const std::string &str){//所有扑克是否正面向上
	if(std::string::npos==str.find_first_of('1'))
		return true;
	else
		return false;
}
void initFlag(){//
	for(std::size_t i=0;i<maxn;++i)
		flag[i]=false;
}
int countFlag(int endId){//统计主动翻动的次数
	int res=0;
	for(std::size_t i=0;i<endId;++i)
	if(flag[i]) ++res;
	return res;
}
void turn(char&a){//翻动
	if('1'==a)
		a='0';
	else 
		a='1';
}
//depth >=2
void getMin(std::string& str,int depth){
	if(depth==str.size()){
		if(isOk(str)){
			int res=countFlag(str.size());
			if(res<times)
				times=res;
		}
		return ;
	}
	getMin(str,depth+1);
	if(depth>0)
		turn(str[depth-1]);
	turn(str[depth]);
	if(depth+1<str.size())
		turn(str[depth+1]);
	flag[depth]=true;
	getMin(str,depth+1);
	//回退,恢复状态
	if(depth>0)
		turn(str[depth-1]);
	turn(str[depth]);
	if(depth+1<str.size())
		turn(str[depth+1]);
	flag[depth]=false;
}
int main(int argc,char** argv){
	std::string str;
	while(std::cin>>str){
		times=INT_MAX;
		initFlag();
		getMin(str,0);
		if(times!=INT_MAX)
			std::cout<<times<<std::endl;
		else std::cout<<"NO"<<std::endl;
	}
}




由于depth只会影响到depth-1,depth,depth+1,所以如果depth-1以前有反面向上,那么,最后isOk肯定是false,可以进行减枝,代码修改为:

void getMin(std::string& str,int depth){
	if(depth==str.size()){
		if(isOk(str)){
			int res=countFlag(str.size());
			if(res<times)
				times=res;
		}
		return ;
	}
	if(depth>=2){
		if(str[depth-2]=='1')
			return ;
	}
	getMin(str,depth+1);
	if(depth>0)
		turn(str[depth-1]);
	turn(str[depth]);
	if(depth+1<str.size())
		turn(str[depth+1]);
	flag[depth]=true;
	getMin(str,depth+1);
	//回退,恢复状态
	if(depth>0)
		turn(str[depth-1]);
	turn(str[depth]);
	if(depth+1<str.size())
		turn(str[depth+1]);
	flag[depth]=false;
}




此方法在hdu提交成功,在hero提交提示代码异常,不知道为什么了,调了半天!

还可以通过depth步为了确保depth-1为正面向上而主动翻动来进行优化。可以参见/article/2664050.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: