加载中...

0 1转换 求最小的次数 于是最多只能操作1次(操作2次相当于没操作)

费解的开关https://www.acwing.com/problem/content/97/

因为当第一行的操作定下来后那么下面的每个操作就减少了
而我们需要枚举第一行的每个状态 按下第一行的每个开关 无论是亮的还是暗的 以达到每一个解
然后再从第一行开始遍历每一个解

第一行的按法(在这里 1 表示按了, 0 表示不按),这里只是为了输出第一行按完之后的状态


char g[N][N], backup[N][N];
int dx[5] = {-1, 0, 1, 0, 0}, dy[5] = {0, 1, 0, -1, 0};

void turn(int x, int y)
{
    for (int i = 0; i < 5; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= 5 || b < 0 || b >= 5) continue;   // 在边界外,直接忽略即可
        g[a][b] ^= 1;
    }
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        for (int i = 0; i < 5; i ++ ) cin >> g[i];

        int res = 10;
        for (int op = 0; op < 32; op ++ )
        {
            memcpy(backup, g, sizeof g);
            int step = 0;
            for (int i = 0; i < 5; i ++ )//操作第一行
                if (op >> i & 1)//看看第几位数字是1;
                {
                    step ++ ;
                    turn(0, i);
                }

            for (int i = 0; i < 4; i ++ )//第一行到第四行
                for (int j = 0; j < 5; j ++ )
                    if (g[i][j] == '0')
                    {
                        step ++ ;
                        turn(i + 1, j);//下一行要开
                    }

            bool dark = false;
            for (int i = 0; i < 5; i ++ )//第五行每一个都看看
                if (g[4][i] == '0')
                {
                    dark = true;//发现最后一行还有黑的那么就是-1
                    break;
                }

            if (!dark) res = min(res, step);//没有暗的 获得最小数
            memcpy(g, backup, sizeof g);
        }

        if (res > 6) res = -1;

        cout << res << endl;
    }

    return 0;
}


飞行员兄弟(01最优解是每个把手只按一次)https://www.acwing.com/problem/content/118/

状态压缩+ dfs
每次修改4*4的点阵 修改可以将所在的行和列也同时修改掉

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 5;

char g[N][N], backup[N][N];//

int get(int x, int y)//获取坐标
{
    return x * 4 + y;
}

void turn_one(int x, int y)//修改点
{
    if (g[x][y] == '+') g[x][y] = '-';
    else g[x][y] = '+';
}

void turn_all(int x, int y)//修改行
{
    for (int i = 0; i < 4; i ++ )
    {
        turn_one(x, i);
        turn_one(i, y);
    }

    turn_one(x, y);//多修改了一次
}

int main()
{
    for (int i = 0; i < 4; i ++ ) cin >> g[i];

    vector<PII> res;
    for (int op = 0; op < 1 << 16; op ++ )//这里相当于枚举(给你个蓝图 按照蓝图上的做) 二进制里面的每个1代表操作对应的位置需要操作 按照操作完之后 如果成功就放入
    {
        vector<PII> temp;
        memcpy(backup, g, sizeof g);        // 备份 只用g操作

        // 进行操作
        for (int i = 0; i < 4; i ++ )
            for (int j = 0; j < 4; j ++ )
                if (op >> get(i, j) & 1)
                {
                    temp.push_back({i, j});
                    turn_all(i, j);
                }

        // 判断所有灯泡是否全亮
        bool has_closed = false;
        for (int i = 0; i < 4; i ++ )
            for (int j = 0; j < 4; j ++ )
                if (g[i][j] == '+')
                    has_closed = true;//操作到这里的时候 全是+号

        if (has_closed == false)
        {
            if (res.empty() || res.size() > temp.size()) res = temp;//如果是空的就一定要放,如果tenp放入的个数小就也要操作
        }

        memcpy(g, backup, sizeof g);        // 还原
    }

    cout << res.size() << endl;
    for (auto op : res) cout << op.x + 1 << ' ' << op.y + 1 << endl;

    return 0;
}



翻硬币

可以反转左右两边 干脆从第一个开始 向右反转 反转到倒数第二个就可以了


void turn(int i){
    if(a[i]=='*') a[i]='o';
    else a[i]='*';
}
int main()
{
    cin >> a>>b;
    int res=0;
    for (int i = 0; i+1 < a.size(); i ++ ){
        if(a[i]!=b[i]){
            turn(i),turn(i+1);res++;
        }
    }
    cout << res;
    return 0;
}
posted @ 2022-02-23 22:31  liang302  阅读(131)  评论(0编辑  收藏  举报