无标题无标题

发布时间:2024年01月10日

???

ABC Puzzle

326D

题意:给两个长n的仅由ABC组成的字符串s1,s2,是否在n*n阵列中满足以下条件,若满足则输出,不满足输出No

? 条件1:每行每列仅包含一个A,一个B,一个C ? ? ? ? ? (3<=n<=5)
? 条件2:第i行最左边的字符恰好是s1的第i个字符
? 条件3:第i列最上边的字符恰好是s2的第i个字符

输入样例: ? ? ? ? ? ? 输出样例:
5? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Yes
ABCBC? ? ? ? ? ? ? ? ? ? AC..B
ACAAB? ? ? ? ? ? ? ? ? ? .BA.C
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C.BA.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? BA.C.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ..CBA
思路:

一道比较恶心的dfs题。

说一下dfs思路吧:

依次放每个格子可以放.? 也可以放A或B或C这四种选择。然后全部放完就检查一下即可。因为走错就要回溯,这最大妥妥的4^25根本过不去。首先主要到每行每列最多两个. 那么就要加以剪枝。

设置cnt[0][i][?]表示第i行已经有几个. 字符,cnt[1][i][?]对应第i列已经有几个. 字符?(剪枝1)

if(cnt[0][x]['.']<n-3&&cnt[1][y]['.']<n-3){//这是放"."的情况,每行列最多放两个,因为只放一次,所以if语句即可
	an[x][y]='.';
	cnt[0][x]['.']++;cnt[1][y]['.']++;
	dfs(x,y+1);
	cnt[0][x]['.']--;cnt[1][y]['.']--;
	}

?然后是放置3种字母。首先是看看同行是否已经有该字符。同样设置cnt[0][x][c]代表第x行是否有该字符,cnt[1][y][c]代表第y行是否有该字符。(剪枝2)

????????接着是看是否和原字符串的对应位置匹配。第一个字符串对应x行,第二个字符串对应y列,我们如果swap后如果传入的是s[0][x]是0,那么自动返回1,这种情况就对应已经有了开头字符了。如果没有开头字符那就直接和开头字符比较看是否相同。(剪枝3)

for(char c='A';c<='C';c++){//放3种字母
	if(cnt[0][x][c]==0&&cnt[1][y][c]==0){//第x行y列是否都没有该字符
		if(match(s[0][x],c)&&match(s[1][y],c)){
//开头都确定,开头一个确定另一个不确定但相等,开头都不确定但都相等
			an[x][y]=c;
			char tmp=0,tmp2=0;
			swap(tmp,s[0][x]);//0和0交换(开头已经确定),0和非0交换(开头未确定变已确定)
			swap(tmp2,s[1][y]);
			cnt[0][x][c]++;cnt[1][y][c]++;
			dfs(x,y+1);
			cnt[1][y][c]--;cnt[0][x][c]--;//失败,回溯(回溯尽量去swap,这样更容易恢复状态)
			swap(tmp,s[0][x]);//交换回来
			swap(tmp2,s[1][y]);
			}
		}
	}

好了,经过以上的剪枝,这个dfs就能过去了?

#include <bits/stdc++.h>
using namespace std;
int n;
int cnt[2][5][128];//cnt[0][i][?]表示第i行已经有几个?字符(ASCII),cnt[1][i][?]对应相关列
char an[5][7];//答案阵列
string s[2];
bool match(char c1,char c2){
	if(!c1)return 1;//如果说传过来的s[0,1][?]对应第?行,列已经有开头字符了(将会传过来0),那就直接返回正确
	return c1==c2;//否则就去比较这两个字符
}
//void型dfs 中return其实可有可无,其实就相当于是函数的continue功能,是为了防止进入走后面的代码,引发错误!
//dfs中的标记变量,一定要设置为局部变量,避免被别的dfs给修改
void dfs(int x,int y){//其实每个格子都有4种选择,不见得非ABC就要回溯,一定要细心
	if(x==n){
		cout<<"Yes\n";
		for(int i=0;i<n;i++)cout<<an[i]<<'\n';
		exit(0);//任务完全直接结束
	}
	if(y==n){dfs(x+1,0);return ;}
	if(cnt[0][x]['.']<n-3&&cnt[1][y]['.']<n-3){//这是放"."的情况,每行列最多放两个,因为只放一次,所以if语句即可
		an[x][y]='.';
		cnt[0][x]['.']++;cnt[1][y]['.']++;
		dfs(x,y+1);
		cnt[0][x]['.']--;cnt[1][y]['.']--;
	}
	for(char c='A';c<='C';c++){、、放3种字母
		if(cnt[0][x][c]==0&&cnt[1][y][c]==0){//第x行y列是否都没有该字符
			if(match(s[0][x],c)&&match(s[1][y],c)){
//开头都确定,开头一个确定另一个不确定但相等,开头都不确定但都相等
				an[x][y]=c;
				char tmp=0,tmp2=0;
				swap(tmp,s[0][x]);//0和0交换(开头已经确定),0和非0交换(开头未确定变已确定)
				swap(tmp2,s[1][y]);
				cnt[0][x][c]++;cnt[1][y][c]++;
				dfs(x,y+1);
				cnt[1][y][c]--;cnt[0][x][c]--;//失败,回溯(回溯尽量去swap,这样更容易恢复状态)
				swap(tmp,s[0][x]);//交换回来
				swap(tmp2,s[1][y]);
			}
		}
	}
}
int main(){
	cin>>n;
	for(int i=0;i<2;i++)cin>>s[i];
	dfs(0,0);
	cout<<"No\n";
}
文章来源:https://blog.csdn.net/m0_69478376/article/details/135511888
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。