2024天梯赛【搜索】

吉利矩阵

题目大意

image

dfs思路

  • 搜索策略:每一行每一行的搜索,(1,1)->(1,2)->...->(1,n)->(2,1)->...(n,n)
  • 剪枝策略:记录每一行与每一列的总和,sumRow,sumCol,接下来要填的数要小于等于 l - sumRow[x] 与 l - sumCol[y],如果当前行填完了,要判断当前行sumRow[x]是否等于 l。

题目代码

#include<bits/stdc++.h>
using namespace std;
int g[5][5],sumRow[5],sumCol[5];
int l,n,cnt;
void dfs(int x,int y){
    if(x == n + 1){
        ++cnt;return;
    }
    for(int i = 0;i <= min(l - sumRow[x],l - sumCol[y]);++i){
        sumRow[x] += i;sumCol[y] += i;
        if(y < n) dfs(x,y + 1);
        else if(y == n && sumRow[x] == l) dfs(x + 1,1);
        sumRow[x] -= i;sumCol[y] -= i;
    }
}
int main(){
    cin >> l >> n;
    dfs(1,1);
    cout << cnt << '\n';
}

类似题目

题目链接

https://atcoder.jp/contests/abc326/tasks/abc326_d

题目代码1

#include<bits/stdc++.h>
using namespace std;

int n;string r,c;
vector<bool>lft(6,false),top(6,false);
vector<int>row(6,0),col(6,0);
vector<vector<char>>g(6,vector<char>(6,'.'));
bool flag = false;
void dfs(int x,int y){
	if(flag) return;
	if(x == n){
		for(int i = 0;i < n;++i) if(row[i] != 7) return;
		for(int j = 0;j < n;++j) if(col[j] != 7) return;
		cout << "Yes" << '\n';
		for(int i = 0;i < n;++i){
			for(int j = 0;j < n;++j){
				cout << g[i][j];
			}
			cout << '\n';
		}
		flag = true;
		return;
	}
	bool lleft = lft[x],ttop = top[y];
	for(int i = 0;i < 3;++i){
		char v = 'A' + i;
		if((row[x] >> i) & 1 || (col[y] >> i) & 1) continue;
		if(!ttop){
			if(c[y] != v) continue;
			else          top[y] = true;
		}
		if(!lleft){
			if(r[x] != v) {
				// 这里也要复原,不然就WA了,找了半天! 
				top[y] = ttop;
				continue;
			}
			else          lft[x] = true;
		}
		row[x] |= (1 << i);col[y] |= (1 << i);g[x][y] = v;
		if(y == n - 1){
			if(row[x] == 7) dfs(x + 1,0);
		}else dfs(x,y + 1);
		lft[x] = lleft;top[y] = ttop;
		row[x] ^= (1 << i);col[y] ^= (1 << i);g[x][y] = '.';
	}
	if(y == n - 1){
		if(row[x] == 7) dfs(x + 1,0);
	}else dfs(x,y + 1);
}
int main(){
	cin >> n >> r >> c;
	dfs(0,0);
	if(!flag) cout << "No\n";
	return 0;
}

题目代码2

#include<bits/stdc++.h>
using namespace std;

int n;string r,c;
vector<vector<string>>row(3);
vector<string>g;
bool flag;
void dfs(int i,int x){
	if(flag) return;
	if(i == n){
		if(x == 0){
			cout << "Yes\n";
			for(auto &nx:g) cout << nx << '\n';
			flag = true;
		}
		return;
	}
	for(auto &nx:row[r[i] - 'A']){
		g.push_back(nx);
		int tmp = x;
		bool flag1 = true;
		for(int j = 0;j < n;++j){
			if(nx[j] == '.') continue;
			int y = nx[j] - 'A';
			// y已经被选过了
			if((x & (1 << (4 * j + y))) == 0) {
				flag1 = false;break;
			}
			tmp ^= (1 << (4 * j + y));
			// 判断y是否是填的第一个数字,如果是的话,一定要等于c[j]!
			if((x & (1 << (4 * j + 3))) != 0){
				if(nx[j] != c[j]) {
					flag1 = false;break;
				}
				tmp ^= (1 << (4 * j + 3));
			}
 		}
 		if(flag1) dfs(i + 1,tmp);
 		g.pop_back();
	}
}
int main(){
	cin >> n >> r >> c;
	string abc = "ABC";
	while(abc.size() < n) abc.push_back('.');
	sort(abc.begin(),abc.end());
	do{
		char tmp;
		for(auto x:abc){
			if(x != '.'){
				tmp = x;break;
			}
		}
		row[tmp-'A'].push_back(abc);
	}while(next_permutation(abc.begin(),abc.end()));
	dfs(0,(1 << (4 * n)) - 1);
	if(!flag) cout << "No\n";
	return 0;
}
posted @ 2024-04-23 11:12  gebeng  阅读(87)  评论(0)    收藏  举报