• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
砖块,费解的开关 (递推)

题目1

砖块

思路 (递推)

​ 我们可以通过题目条件,找出来本题的一些性质

  • 每两个相邻砖块至多操作一次

​ 通过这个性质,我们可以递推的求每个砖块是否被操作,假设砖块变成白色,如果操作第\(i\)个和第\(i + 1\)砖块后,不能使第\(i\)个砖块变为W, 则不进行该操作,因为后续操作无法使该砖块变为W。黑色同理

Code

#include <iostream>
#include <vector>

using i64 = long long;

void solve() {
	int n;
	std::string t;

	std::cin >> n >> t;

	std::vector<int> act1, act2;

	int ans1, ans2;

	ans1 = ans2 = 0;


// 	bool a1 = true, a2 = true;

// 	for(auto &x: t) {
// 		if(x != 'W') a1 = false;
// 		if(x != 'B') a2 = false;
// 	}

// 	if(a1 || a2) {
// 		return puts("0"), (void) 0;
// 	}


	auto flip = [](char &a) {
		a = (a == 'W'?'B':'W');
	};
	
	std::string t2 = t;


	for(int i = 0; i < (int)t2.size() - 1; i ++) {
		flip(t2[i]), flip(t2[i + 1]);	

		if(t2[i] != 'W') {
			flip(t2[i]), flip(t2[i + 1]);
		} else {
			ans1 ++, act1.push_back(i);
		}
	}

	bool st1 = true;

	for(auto &x: t2) {
		if(x != 'W') st1 = false;
	}

	if(!st1) ans1 = 0x3f3f3f3f;
	
	t2 = t;

	for(int i = 0; i < (int) t2.size() - 1; i ++) {
		flip(t2[i]), flip(t2[i + 1]);	

		if(t2[i] != 'B') {
			flip(t2[i]), flip(t2[i + 1]);
		} else {
			ans2 ++, act2.push_back(i);
		}
	}

	bool st2 = true;
	
	
	for(auto &x: t2) {
		if(x != 'B') st2 = false;
	}

	if(!st2) ans2 = 0x3f3f3f3f;

	if(!st1 && !st2) {
		puts("-1");
	} else if(ans1 < ans2) {
		std::cout << ans1 << "\n";

		for(int i = 0; i < ans1; i ++) {
			std::cout << act1[i] + 1 << " \n"[i == ans1 - 1];
		}
	} else {
		std::cout << ans2 << "\n";

		for(int i = 0; i < ans2; i ++) {
			std::cout << act2[i] + 1 << " \n"[i == ans2 - 1];
		}
	}
}

int main() {
	int _;

	std::cin >> _;

	while(_ --) {
		solve();
	}
}

题目2

费解的开关

思路 (递推)

​ 性质:每个灯至多被操作一次

​ 这道题做过很多次了,属于是典中典的题了,我们一行一行的递推,我们先枚举第一行的状态,然后对于当前的状态依次往下递推,如果第\(i - 1\)行的灯没有被点亮那么我们的状态是确定的,即第\(i - 1\) 行的灯只能被第\(i\)行点亮,并且如果第\(i\)行的灯没有被点亮,则第\(i - 1\)行不能进行操作, 所以第\(i - 1\)行的灯确定了第\(i\)行的操作。

Code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f

using i64 = long long;

/*
	性质: 
	每盏灯最多操作一次
	
	思路: 先枚举第一行的状态, 然后进行递归

	第一行的状态确定了,第二行的状态也自然确定了!
*/

char a[10][10], tmp[10][10];

int dx[] = {0, 1, -1, 0}, dy[] = {1, 0, 0, -1};

int ans;

void flip(char &x) {
	x = (x == '0'?'1':'0');
}

bool check(int x, int y) {
	return x >= 1 && x <= 5 && y >= 1 && y <= 5;
}

void four_flip(int x, int y) {
	flip(tmp[x][y]);

	for(int j = 0; j <= 3; j ++) {
		int tx = x + dx[j], ty = y + dy[j];
		if(check(tx, ty)) {
			flip(tmp[tx][ty]);
		}
	}
}

bool check(char a[]) {
	for(int i = 1; i <= 5; i ++) {
		if(a[i] != '1') return false;
	}
	return true;
}

void dfs(int u, int cnt) {

	for(int j = 1; j <= 5; j ++) {
		if(tmp[u - 1][j] != '1') {
			four_flip(u, j);
			cnt ++;

			if(cnt > 6) return;
		}
	}

	if(u == 5) {
		if(check(tmp[u])) {
			ans = std::min(ans, cnt);
		}
		return;
	}


	dfs(u + 1, cnt);
}

void solve() {
	ans = INF;
	
	for(int i = 1; i <= 5; i ++) {
		for(int j = 1; j <= 5; j ++) {
			std::cin >> a[i][j];
		}
	}

	for(int s = 0; s < (1<<5); s ++) {
		memcpy(tmp, a, sizeof a);

		int cnt = 0;

		for(int j = 0; j < 5; j ++) {
			if(s >> j & 1) {
				cnt ++;
				four_flip(1, j + 1);
			}
		}

		// tmp[1][6] = '\0';

		// printf("%s\n\n", tmp[1] + 1);
		dfs(2, cnt);
	}


	std::cout << (ans <= 6?ans:-1) << "\n";
}

int main() {
	int _;

	std::cin >> _;

	while(_ --) {
		solve();
	}
}
posted on 2023-03-02 16:39  Jack404  阅读(9)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3