2020 寒假记录

Posted czc1999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020 寒假记录相关的知识,希望对你有一定的参考价值。

2020 冬 寒假记录(一)

费解的开关

https://vijos.org/p/1197

当第 (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. 每个开关只按一次,因为按两次等于没有按,所以按的次数的最大值就是开关的总数目。
  2. 如果存在解,那么按的顺序是无所谓的。
  3. 每个开关的状态会被后面的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
", 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;
}

以上是关于2020 寒假记录的主要内容,如果未能解决你的问题,请参考以下文章

2020 寒假记录

2020寒假训练记录

2020/1/27寒假自学——学习进度报告7

2020年寒假第7次学习进度记录

2020寒假学习记录——Spark及其生态圈的了解

窦小凤2020寒假学习心得