2020 冬 寒假记录(一)
费解的开关
当第 \(i\) 行的状态确定了之后,只有第 \(i+1\) 行可以影响它,也就是翻完第一行后,后面每一行的操作也就是确定的了,所以枚举第一行的32种状态即可。
深搜
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int dir[4][2] = { {0,-1},{0,1},{-1,0},{1,0} }, ans;
bool maze[7][7];
void infect(int x, int y) {
maze[x][y] = !maze[x][y];
for (int i = 0; i < 4; i++) {
int tox = x + dir[i][0], toy = y + dir[i][1];
maze[tox][toy] = !maze[tox][toy];
}
}
void dfs(int k, int x, int y) {
if (k > 6)return;
if (x == 6) {
int i = 1;
for (; i <= 5; i++) {
if (!maze[5][i])break;
}
if (i == 6) {
ans = k < ans ? k : ans;
}
return;
}
if (x == 1) {
dfs(k, x + y / 5, y % 5 + 1);
infect(x, y);
dfs(k + 1, x + y / 5, y % 5 + 1);
infect(x, y);
}
else {
if (!maze[x - 1][y]) {
infect(x, y);
dfs(k + 1, x + y / 5, y % 5 + 1);
infect(x, y);
}
else
dfs(k, x + y / 5, y % 5 + 1);
}
}
int main() {
int T;
cin >> T;
getchar();
while (T--) {
ans = 1 << 30;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
maze[i][j] = (getchar() == '0' ? false : true);
}
getchar();
}
if (T != 0)
getchar();
dfs(0, 1, 1);
if (ans == (1 << 30)) {
cout << -1 << endl;
}
else {
cout << ans << endl;
}
}
return 0;
}
位图枚举
32种状态,枚举0~31,5位二进制,1表示翻,0表示不翻
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int dir[4][2] = { {0,-1},{0,1},{-1,0},{1,0} }, ans;
bool maze[7][7], temp[7][7];
void infect(int x, int y) {
maze[x][y] = !maze[x][y];
for (int i = 0; i < 4; i++) {
int tox = x + dir[i][0], toy = y + dir[i][1];
maze[tox][toy] = !maze[tox][toy];
}
}
int main() {
int T;
cin >> T;
getchar();
while (T--) {
int res = 7;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
temp[i][j] = (getchar() == '0' ? false : true);
}
getchar();
}
if (T != 0) getchar();
for (int op = 0; op < 32; op++) {
int steps = 0;
memcpy(maze, temp, sizeof(temp));
for (int j = 0; j < 5; j++) {
if ((op >> j) & 1) {
infect(1, j + 1);
steps++;
}
}
for (int i = 2; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (!maze[i - 1][j]) {
infect(i, j);
steps++;
}
}
}
int i = 1;
for (; i <= 5; i++) {
if (!maze[5][i])break;
}
if (i == 6) {
if (steps < 7) {
res = steps < res ? steps : res;
}
}
}
if (res != 7)cout << res << endl;
else cout << -1 << endl;
}
return 0;
}
翻硬币
https://www.acwing.com/problem/content/description/1210/
总结一下类似开关、翻转问题,有以下特点:
- 每个开关只按一次,因为按两次等于没有按,所以按的次数的最大值就是开关的总数目。
- 如果存在解,那么按的顺序是无所谓的。
- 每个开关的状态会被后面的1个或者多个开关影响。
我们已经知道了按的顺序是无所谓的,就从左往右按,那么前面一个硬币,只有紧跟在后边的一个硬币会影响到它。
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
string origin, destination;
int main() {
int cnt = 0;
cin >> origin >> destination;
for (int i = 0; i < origin.length(); i++) {
if (origin[i] != destination[i]) {
cnt++;
origin[i] = origin[i] == '*' ? 'o' : '*';
origin[i + 1] = origin[i + 1] == '*' ? 'o' : '*';
if (origin.compare(destination) == 0) {
cout << cnt << endl;
return 0;
}
}
}
return 0;
}
带分数
https://www.acwing.com/problem/content/description/1211/
之前没有过这种思维,逐个 dfs ,和枚举思想差不多,但是比枚举方便了很多。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int N, res = 0;
bool vis[10];
bool check(int k,int a,int c) {
int b = (N - a) * c;
bool temp[10];
memcpy(temp, vis, 10);
while(b) {
int index = b % 10;
if (!index || temp[index]) return false;
temp[b % 10] = true;
b /= 10;
k++;
}
if (k == 9)return true;
return false;
}
void dfs_c(int k,int a,int c) {
if (a >= N)return;
if (check(k, a, c)) {
res++;
return;
}
for (int i = 1; i <= 9; i++) {
if (!vis[i]) {
vis[i] = true;
dfs_c(k + 1,a, c * 10 + i);
vis[i] = false;
}
}
}
void dfs_a(int k, int a) {
if (a >= N)return;
if (a > 0)
dfs_c(k, a, 0);
for (int i = 1; i <= 9; i++) {
if (!vis[i]) {
vis[i] = true;
dfs_a(k + 1, a * 10 + i);
vis[i] = false;
}
}
}
int main() {
cin >> N;
//N = a + b / c;
//b=(N-a)*c
dfs_a(0, 0);
cout << res << endl;
return 0;
}
The Pilots Brothers‘ refrigerator
http://poj.org/problem?id=2965
DFS
因为“ If there are several solutions, you may give any one of them. ”,搜到第一个就完事了
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int path[20][2];
bool flag;
char maze[5][5];
bool check() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (maze[i][j] == '+')
return false;
}
}
return true;
}
void conver(int x, int y) {
for (int i = 0; i < 4; i++) {
maze[x][i] = maze[x][i] == '+' ? '-' : '+';
maze[i][y] = maze[i][y] == '+' ? '-' : '+';
}
maze[x][y] = maze[x][y] == '+' ? '-' : '+';
}
void dfs(int cnt, int x, int y) {
if (flag)return;
if (check()) {
cout << cnt << endl;
for (int i = 0; i < cnt; i++) {
printf("%d %d\n", path[i][0], path[i][1]);
}
flag = true;
return;
}
if (x == 4)return;
dfs(cnt, x + (y + 1) / 4, (y + 1) % 4);
path[cnt][0] = x + 1; path[cnt][1] = y + 1;
conver(x, y);
dfs(cnt + 1, x + (y + 1) / 4, (y + 1) % 4);
conver(x, y);
}
int main() {
for (int i = 0; i < 4; i++) {
cin >> maze[i];
}
dfs(0, 0, 0);
return 0;
}
位图枚举
#include <iostream>
#include <cstring>
using namespace std;
int maze[5][5], backup[5][5];
void conver(int x, int y) {
for (int i = 0; i < 4; i++) {
maze[x][i] ^= 1;
maze[i][y] ^= 1;
}
maze[x][y] ^= 1;
}
bool check() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (maze[i][j] == 0)
return false;
}
}
return true;
}
int main() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
backup[i][j] = (getchar() == '+') ? 0 : 1;
}
getchar();
}
int res = 0, mmin = 1 << 30;
int len = 1 << 16;
//按要求自上而下自左而右
for (int op = 0; op < len; op++) {
memcpy(maze, backup, sizeof(int) * 5 * 5);
int cnt = 0;
for (int k = 0; k < 16; k++) {
if ((op >> k) & 1) {
cnt++;
conver(k / 4, k % 4);
}
}
if (check() && cnt < mmin) {
mmin = cnt;
res = op;
}
}
cout << mmin << endl;
for (int k = 0; k < 16; k++) {
if ((res >> k) & 1) {
cout << (k / 4) + 1 << ' ' << (k % 4) + 1 << endl;;
}
}
return 0;
}
原文地址:https://www.cnblogs.com/czc1999/p/12183287.html
时间: 2024-10-29 19:09:56