大体题意:一个冰箱上有4*4共16个开关,改变任意一个开关的状态(即开变成关,关变成开)时,此开关的同一行、同一列所有的开关都会自动改变状态。要想打开冰箱,要所有开关全部打开才行。 输入:一个4×4的矩阵,+表示关闭,-表示打开; 输出:使冰箱打开所需要执行的最少操作次数,以及所操作的开关坐标。

 

最开始自己是状压bfs+队列+模拟取反,然后T了。看了博客,大佬是各种优化,数组模拟队列+预处理异或值。

我用这种方法就A了,我把数组模拟队列+模拟取反,结果刚刚1000ms卡过。233333333333333333

正解还可以用高斯消元,我会高斯消元的模板,以后再更新高斯消元的做法。

 

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;

bool vis[700000];

int flip[4][4]={63624,62532,61986,61713,    ///预处理的异或值
36744,20292,12066,7953,
35064,17652,8946,4593,
34959,17487,8751,4383};

struct node
{
    int status;
    int x;
    int y;
    int pre;
}q[1<<16];

int main()
{
    int num=0,top=0,up=1,n;
    char x;
    for(int i=4; i>=1; i--)
    {
        for(int j=1; j<=4; j++)
        {
            cin>>x;
            n=x=='-'?0:1;
            num=num+(n<<(i*4-j));
        }
    }
    q[++top]=node{num,-1,-1,-1};
    while(1)
    {
        if(q[top].status==0)
            break;
        for(int i=1; i<=4; i++)
        {
            for(int j=1; j<=4; j++)
            {
                int s=q[top].status^flip[i-1][j-1];     ///更新状态
                if(!vis[s])
                {
                    vis[s]=1;
                    q[++up]=node{s,i,j,top};
                }
            }
        }
        top++;
    }
    stack<pair<int,int> >ans;
    while(q[top].pre!=-1)       ///回溯路径
    {
        ans.push(make_pair(q[top].x,q[top].y));
        top=q[top].pre;
    }
    printf("%d\n",ans.size());
    while(!ans.empty())
    {
        printf("%d %d\n",ans.top().first,ans.top().second);
        ans.pop();
    }
    return 0;
}