题解 P2962 【[USACO09NOV]Lights G】
P2962 [USACO09NOV]Lights G
题解:
双向搜索,已知
在实际编写的过程中
- 每个开关不能被重复使用。
- 需要用二进制来进行表示哪个状态使用过,哪个没有使用过。
- 最后是匹配是使用二进制 ^ 匹配前
n/2 的状态。
代码
#include <map>
#include <queue>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 600;
map<ll,int>mm[2];
vector<int>v[40];
int n,m;
inline ll exchar(ll ch,int x){
if((ch>>x)&1)return ch-((ll)1<<x);
return ch+((ll)1<<x);
}
inline int slove(){
mm[0].clear();
mm[1].clear();
queue<pair<ll,ll> >q;
ll s=0,e=((ll)1<<n)-1;
q.push({s,0});mm[0][s]=0;
while(!q.empty()){
pair<ll,ll>p=q.front();
q.pop();
int k=mm[0][p.first];
for(int i=0;i<n/2;++i){
if((p.second>>i)&1)continue;
pair<ll,ll>pp=p;
pp.second+=((ll)1<<i);
pp.first=exchar(pp.first,i);
for(int j=0;j<v[i].size();++j){
pp.first=exchar(pp.first,v[i][j]);
}
if(mm[0].count(pp.first)==0){
mm[0][pp.first]=k+1;
q.push(pp);
}
}
}
q.push({s,0});mm[1][s]=0;
while(!q.empty()){
pair<ll,ll>p=q.front();
q.pop();
int k=mm[1][p.first];
for(int i=n/2;i<n;++i){
if((p.second>>i)&1)continue;
pair<ll,ll>pp=p;
pp.second+=((ll)1<<i);
pp.first=exchar(pp.first,i);
for(int j=0;j<v[i].size();++j){
pp.first=exchar(pp.first,v[i][j]);
}
if(mm[0].count(pp.first^e)){
return mm[0][pp.first^e]+k+1;
}
if(mm[1].count(pp.first)==0){
mm[1][pp.first]=k+1;
q.push(pp);
}
}
}
return -1;
}
int main(){
int x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<m;++i){
scanf("%d%d",&x,&y);
--x;--y;
v[x].push_back(y);
v[y].push_back(x);
}
printf("%d\n",slove());
return 0;
}