【题解】关灯问题(状压广搜)
2026-08-31 15:14:59
发布于:上海
8阅读
0回复
0点赞
题意解析
有 m 个按钮,每个按钮可以根据情况控制每一个灯泡,一共有 n 个灯泡,一开始所有灯泡都亮着,想要把他们全部关掉。
核心思路:把开着看作0,关着看作1,初始为00000,最后是11111,这样再根据题意模拟灯泡的控制,进行广搜即可。
下面是代码参考:
#include<bits/stdc++.h>
using namespace std;
#define int long long//习惯long long
const int N=12;
int n,m;
int vis[1<<N]; //vis数组记录哪几个状态访问过
vector<int>c[110];
signed main(){
cin>>n>>m;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
int x;
cin>>x;
c[i].push_back(x);
}
}
queue<pair<int,int>>q;
vis[0]=1;
q.push({0,0}); //用队列内部记录步数,之前吃了大亏,用数组记录了
int ans=1e18;//记录最小步数
while(q.size()){
int s=q.front().first;
int step=q.front().second;
q.pop();
if(s==((1<<n)-1)){
ans=min(ans,step);//到达11111
continue;//到了就不要继续了
}
for(int i=0;i<m;i++){
int ns=s;
for(int j=0;j<n;j++){
int x=c[i][j];
if(x==1 && (!(ns&(1<<j)))){ //由于位运算优先级特别高
//不妨使用顶级优先级的括号呢
ns|=(1<<j);//原来0是开着,现在让它变成1,代表关着
}else if(x==-1 && (ns&(1<<j))){
ns^=(1<<j);
}
}
if(!vis[ns]){
vis[ns]=1;
q.push({ns,step+1});
}
}
}
if(vis[(1<<n)-1]==0){ //不要忘记题意,如果无法到达,输出-1
cout<<-1;
return 0;
}
cout<<ans;
return 0;
}
这里空空如也




有帮助,赞一个