【A - 棋盘问题】

80 篇文章 0 订阅
80 篇文章 0 订阅

注:由于本专题名声在外,且是在 VJ 平台上,一般大家都会找 cloned 比赛做,就不放链接了,在此一并解释。

思路:

  • 第一版代码是写的比较熟的 dfs,但是 TLE,也不会分析原因。

  • 第二版是借鉴syyyyyw的BLOG。方法很简便,略作讲解:

    1. 因为要求棋子不可以在同一行同一列,所以其实【每翻一个格子一并确定哪些格子不能翻,搜索后再翻回来】的操作就很难实现(因为有重叠的格子)(可以通过拷贝实现,详参见写过的m皇后问题,但是TLE无疑)。
    2. 因此,采用枚举的思想,每一行去深搜,注意 main 中从第 i 行开始的深搜代表前 i 行的格子都不用。如此,只记录每列是否 vis 即可。
  • 注意:在第二版代码中,增强如下判断反而会使时间增加到 63ms

for(int i=1;i+k-1<=n;i++){
	for(int j=1;j<=n;j++)
		if(mp[i][j]){
			memset(vis,0,sizeof(vis));
			dfs(i,j,1);
		}
}

代码:

  • TLE
#include <iostream>
#include <cstring>
#include <set>

using namespace std;

int n,k;
bool mp [10][10];
bool vis[10][10];
int ans;


void init(){
	memset(vis,false,sizeof(vis));
	ans = 0;
	return ;
}

void flip(int x,int y){
	vis[x][y] = !vis[x][y];
	return ;
}

bool judge(){
	set<int> row;
	set<int> col;
	int t=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(vis[i][j]){
				row.insert(i);
				col.insert(j);
			}
		}
	}
	if(row.size() == col.size()){
		ans++;
		return true;
	}
	return false;
}

void dfs(int x,int y,int deep){
	//放完了 deep 个棋子 
	if(deep == k){
		judge();
		return ;
	}
	if(x > n) return ;
	
	if(mp[x][y]){
		flip(x,y);
		if(y != n)
			dfs(x , y+1 , deep+1);
		else
			dfs(x+1 , 1 , deep+1);
		flip(x,y);
	}
	if(y != n)
		dfs(x , y+1 , deep);
	else
		dfs(x+1 , 1 , deep);
	return ;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(true){
		cin>>n>>k;
		init();
		if(n == k && n == -1)
			break;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				char t;
				cin>>t;
				mp[i][j] = t == '#' ? true : false;
			}
		dfs(1,1,0);
		cout<<ans<<endl;
	}
	return 0;
}
  • 47ms 672kB
//47ms  672kB


#include <iostream>
#include <cstring>

using namespace std;

int n,k;
bool mp[10][10];
int ans;
bool vis[10];

void init(){
	memset(mp,false,sizeof(mp));
	ans = 0;
	return ;
}

void dfs(int x,int y,int deep){
	//x,y 已放,放完了 deep 个 
	if(deep == k){
		ans++;
		return ;
	}
	vis[y] = true ;
	for(int i=x+1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(mp[i][j] && !vis[j])
				dfs(i,j,deep+1);
		}
	}
	vis[y] = false;
	return ;
}


int main(){
	while(true){
		cin>>n>>k;
		if(n == -1 && k == -1)
			break;
		init();
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				char temp;
				cin>>temp;
				if(temp == '#')
					mp[i][j] = true;
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++)
				if(mp[i][j]){
					memset(vis,0,sizeof(vis));
					dfs(i,j,1);
				}
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值