【ACwing】一、基础算法:1.4飞行员兄弟

题目:
在这里插入图片描述
输入样例:

-+--
----
----
-+--

输出样例:

6
1 1
1 3
1 4
4 1
4 3
4 4

首先理解下题意,下面是样例的运行过程:
在这里插入图片描述
分析:
算一下直接使用暴力的复杂度,已知4×4的矩阵共16个数,也就是起始可以改变的位置有16个,在每个起始状态下最坏会对16个数依次进行翻转。那么复杂度是 O ( 1 6 16 ) O(16^{16}) O(1616) 运行次数会超限制。可以考虑用二进制数 2 16 2^{16} 216的每一位的数值来标记16个数是否被翻转,也就是16位数的每一位有0/1两个状态(而起始状态仍为16个),这样复杂度会变成 O ( 16 × 2 16 ) O(16×2^{16}) O(16×216)

代码的过程理解如下: 在这里插入图片描述

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
char a[5][5];//原始输入矩阵
char b[5][5];//中间变化后的矩阵
vector <pair<int,int>> ans;//记录最少翻转步骤
vector <pair<int,int>> tmp2;//中间翻转步骤
//翻转同行同列以及本身
void turn(int n)
{
    int x=n/4+1;
    int y=n%4+1;
    tmp2.push_back(make_pair(x,y));//记录每种状态下的翻转步骤
    for(int i=1; i<=4; i++)
    {
        b[x][i] = b[x][i] == '+' ? '-' : '+';//同行
        b[i][y] = b[i][y] == '+' ? '-' : '+';//同列
    }
    b[x][y]=b[x][y]=='+'?'-':'+';//本身
}

//判断当前是否全部打开
int test()
{
    for(int i=1; i<=4; i++)
        for(int j=1; j<=4; j++)
            if(b[i][j]=='+')
                return 0;
}
int main()
{

    for(int i=1; i<=4; i++)
        for(int j=1; j<=4; j++)
            cin>>a[i][j];

    for(int i=1; i<(1<<16); i++)//每个初始状态对应的结果都要进行判断是否全部打开
    {
        memcpy(b, a, sizeof a); //将a的数据复制到b中
        tmp2.clear();
        int cnt=log(i)/log(2)+1;
        for(int j=0; j<cnt; j++)
        {
            if((i>>j)&1)
                turn(j);
        }

        //如果能全部打开并且所需步数更少,则更新解数组ans
        if(test())
        {
            if(ans.size()==0||ans.size()>tmp2.size())
                ans=tmp2;
        }
    }

    cout<<ans.size()<<endl;
    for(int i=0; i<ans.size(); i++)
        printf("%d %d\n",ans[i].first,ans[i].second);

    return 0;
}
/*
输入:

-+--
----
----
-+--
*/

琐碎的知识点补充:
(1)关于vecter的使用详细介绍看https://blog.csdn.net/msdnwolaile/article/details/52708144
(2)memcpy(b, a, sizeof a);的介绍:

void *memcpy(void *destin, void *source, unsigned n);

作用是:以source指向的地址为起点,将连续的n个字节数据,复制到以destin指向的地址为起点的内存中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值