飞行员兄弟,四种ac代码

题目描述:

“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有16个把手的冰箱。

已知每个把手可以处于以下两种状态之一:打开或关闭。

只有当所有把手都打开时,冰箱才会打开。

把手可以表示为一个4х4的矩阵,您可以改变任何一个位置[i,j]上把手的状态。

但是,这也会使得第i行和第j列上的所有把手的状态也随着改变。

请你求出打开冰箱所需的切换把手的次数最小值是多少。

输入格式

输入一共包含四行,每行包含四个把手的初始状态。

符号“+”表示把手处于闭合状态,而符号“-”表示把手处于打开状态。

至少一个手柄的初始状态是关闭的。

输出格式

第一行输出一个整数N,表示所需的最小切换把手次数。

接下来N行描述切换顺序,每行输入两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。

数据范围
1≤i,j≤4

输入样例:

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

输出样例:

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

注意:如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。

解法:

这里给出四种方法,我每个写完进行过测试,速度从满到快
在这里插入图片描述

1.数组写法,最慢的写法

利用一个char数组保存信息,循环枚举各种可能的方法

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

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N = 5;

char bro[N][N] , backup[N][N];

int get(int x,int y ){
    return x*4+y;
}


void turn_one(int x,int y)
{
    if(bro[x][y] == '+') bro[x][y] = '-';
    else    bro[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>>bro[i];
    
    vector<PII> res;
    for(int op = 0;op<1<<16;op++)
    {
        vector<PII> tmp;
        memcpy(backup,bro,sizeof bro);
        
        for(int i = 0;i<4;i++)
            for(int j = 0;j<4;j++)
                if(op>>get(i,j)&1)
                {
                    tmp.push_back({i,j});
                    turn_all(i,j);
                }
                
        bool has_close = false;
        for(int i =0;i<4;i++)
            for(int j = 0;j<4;j++)
                if(bro[i][j]=='+'){
                    has_close = true;
                    break;
                }
        if(has_close == false)
        {
            if(res.empty()||res.size()>tmp.size())res = tmp;
        }
        
        memcpy(bro,backup,sizeof bro);
        
    }
    
    cout<<res.size()<<endl;
    
    for(auto c:res)cout<<c.x+1<<' '<<c.y+1<<endl;
    
    return 0;
    
}

2.位优化,比数组快很多

利用一个16位的二进制数的每一位1/0来保存信息,适用于每个位置的信息只有两种情况的题目

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

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N = 4;

int change[N][N];

int get(int x,int y ){
    return x*4+y;
}

int main()
{
    for(int i = 0;i<N;i++)
        for(int j = 0;j<N;j++)
        {
            for(int k = 0;k<N;k++) change[i][j] +=(1<<get(i,k)) + (1<<get(k,j));
            change[i][j] -= 1<<get(i,j);
        }
        
    int state = 0;
    
    for(int i = 0;i<4;i++){
        string s;
        cin>>s;
        for(int j = 0;j<4;j++) 
            if(s[j] == '+') state += 1<<get(i,j);
    }
    
    
    vector<PII> res;
    
    for(int k = 0;k<1<<16;k++)
    {
        int now = state;
        vector<PII> tmp;
        for(int i = 0;i<16;i++)
        {
            if(k>>i&1)
            {
                int a = i/4,b  = i%4;
                now ^= change[a][b];
                tmp.push_back({a,b});
            }
        }
        if(!now && (res.empty()||res.size()>tmp.size())) res = tmp;
    }
    cout<<res.size()<<endl;
    for(auto c:res)cout<<c.x+1<<' '<<c.y+1<<endl;
    
        
    return 0;
    
}

3.dfs,比枚举能优化十倍左右

题中如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。

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

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N = 5;
char g[N][N];
vector<PII> res,tmp;

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);
}



void dfs(int x,int y)
{
    if(x == 3 && y == 4)
    {
        bool success = true;
        for(int i = 0;i<4;i++)
            for(int j = 0; j <4;j++)
            if(g[i][j] == '+'){
                success = false;
                break;
            }
    
    if(success)
        if(res.empty()||tmp.size()<res.size())
            res = tmp;
    return;
    }
    
    if(y == 4)x++,y= 0;
    
    turn_all(x,y);
    tmp.push_back({x,y});
    dfs(x,y+1);
    
    tmp.pop_back();
    turn_all(x,y);
    
    dfs(x,y+1);
}


int main()
{
    for(int i = 0;i<4;i++)scanf("%s",g[i]);
    
    //从0,0开始DFS
    dfs(0,0);
    
    cout<<res.size()<<endl;
    for(auto c:res)cout<<c.x+1<<' '<<c.y+1<<endl;
    
        
    return 0;
    
}

4.dfs+位优化 ,实测比dfs还能快很多

在dfs的基础上加上位优化

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

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;


const int N = 4;

int change[N][N];
vector<PII> res,tmp;
int state = 0;
int now;

int get(int x,int y ){
    return x*4+y;
}



void turn_all(int x,int y)
{
    
    now ^= change[x][y];
}



void dfs(int x,int y)
{
    if(x == 3 && y == 4)
    {
        bool success = true;
        if(now)
            {
                success = false;
            }
    
    if(success)
        if(res.empty()||tmp.size()<res.size())
            res = tmp;
    return;
    }
    
    if(y == 4)x++,y= 0;
    
    turn_all(x,y);
    tmp.push_back({x,y});
    dfs(x,y+1);
    
    tmp.pop_back();
    turn_all(x,y);
    
    dfs(x,y+1);
}


int main()
{
    
    for(int i = 0;i<N;i++)
        for(int j = 0;j<N;j++)
        {
            for(int k = 0;k<N;k++) change[i][j] +=(1<<get(i,k)) + (1<<get(k,j));
            change[i][j] -= 1<<get(i,j);
        }
    
    for(int i = 0;i<4;i++){
        string s;
        cin>>s;
        for(int j = 0;j<4;j++) 
            if(s[j] == '+') state += 1<<get(i,j);
    }
    
    now = state;
    
    //从0,0开始DFS
    dfs(0,0);
        
    cout<<res.size()<<endl;
    for(auto c:res)cout<<c.x+1<<' '<<c.y+1<<endl;
        
    return 0;
    
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值