maninbule / LanQiaoCup

蓝桥杯刷题活动
0 stars 0 forks source link

AcWing 116. 飞行员兄弟 #8

Open maninbule opened 4 years ago

maninbule commented 4 years ago

AcWing 116. 飞行员兄弟 “飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有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
fledglingxx commented 4 years ago
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;

#define x first
#define y second

typedef pair<int,int> pii;

char ch[12][12];
char c[12][12];

int check()
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            if(ch[i][j]=='+') return 0;
        }
    }
    return 1;
}

void turn_one(int x,int y)
{
    if(ch[x][y]=='+') ch[x][y]='-';
    else ch[x][y]='+';
}

void turn(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()
{
    vector<pii>ans;
    for(int i=0;i<4;i++) cin>>ch[i];

    for(int op=0;op<1<<16;op++)
    {
        vector<pii> res;
        memcpy(c,ch,sizeof ch);
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(op>>(i*4+j)&1)
                {
                    res.push_back({i,j});
                    turn(i,j);
                }
            }
        }
        if(check()) 
        {
            if(ans.empty()||ans.size()>res.size()) ans=res;
        }
        memcpy(ch,c,sizeof c);
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++) cout<<ans[i].x+1<<" "<<ans[i].y+1<<endl;
    return 0;
}
maninbule commented 4 years ago

二进制枚举出16个开关所有的状态i,此状态可以用一个int中的16位对应的二进制来表示。对于其中优先级这个,改变次数一样,int大者优先级更高

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
using namespace std;

string s[5];
int mp[5][5],row[5],col[5];
int rescnt = 2e9,res;
bool isok(){
    for(int i =0;i<4;i++){
        for(int j = 0;j<4;j++){
            int cnt = 0;
            if(s[i][j] == '+') cnt = 1;
            cnt += row[i]+col[j]-mp[i][j];
            if(cnt%2 == 1) return false;
        }
    }
    return true;
}

int main(){
    for(int i = 0;i<4;i++) cin>>s[i];
    for(int i = 1;i<(1<<16);i++){
        int changes = 0;
        memset(mp,0,sizeof(mp));
        memset(row,0,sizeof(row));
        memset(col,0,sizeof(col));
        for(int j = 0;j<16;j++){
            if((i>>j)&1){
                row[j/4]++;
                col[j%4]++;
                mp[j/4][j%4]++;
                changes++;
            }
        }
        if(isok()){
            if(changes<rescnt) {
                rescnt = changes;
                res = i;
            }else if(changes == rescnt){
                res = max(res,i);
            }
        }
    }
    cout<<rescnt<<endl;
    for(int j = 0;j<16;j++){
        if((res>>j)&1){
            printf("%d %d\n",j/4+1,j%4+1);
        }
    }

    return 0;
}