Description
贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了。贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊恐,痛苦与绝望。她希望您能够帮帮她,把所有的灯都给重新开起来!她才能继续快乐地跟她的闺密们继续玩游戏!
牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常复杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。
每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开着的时候,这盏灯被关掉;当一盏灯是关着的时候,这盏灯被打开。
问最少要按下多少个开关,才能把所有的灯都给重新打开。
数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。
分析
看到这里的n很小,只有35,就会想到暴力,
可是如果枚举每一个开关的状态,就是
235
这是一个不可以接受的复杂度。
我们就可以考虑折半搜索。
就拿35盏灯来举例
我们将开关分成第1~17和第18~35两个部分。
先用
217
来求出第1~17开关的所有开关状态的对应全局每盏灯的亮的情况。
也就是说我们知道某个全局灯亮的情况对应着需要使用多少个1~17的开关。
这些提前求出了的东西就用一个哈希表存着。
接下来就考虑第18~35个开关,
同样我们枚举每个开关的开与关,也可以知道此时全局灯的亮的情况。
将这些情况与之前求出的状态在哈希表中对应,即可求出答案。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define N 40
#define mo 123454321
#define ll long long
using namespace std;
int n,m,x,y,d;
int tot,next[N*N],a[N*N],b[N],f[N],g[mo],ans;
ll sum,z[N],h[mo];
char ch;
void read(int &n)
{
n=0;
ch=getchar();
while((ch<'0' || ch>'9') && ch!='-')ch=getchar();
int w=1;
if(ch=='-')w=-1,ch=getchar();
while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=getchar();
n*=w;
}
void ins(int x,int y)
{
next[++tot]=b[x];
a[tot]=y;
b[x]=tot;
}
void add(int x)
{
f[x]=1-f[x];
for(int i=b[x];i;i=next[i])
f[a[i]]=1-f[a[i]];
}
void hs(ll s,int y)
{
int x=s%mo;
while(h[x]!=0 && h[x]!=s)x=(x+1)%mo;
g[x]=min(g[x],y);
h[x]=s;
}
int find(ll s)
{
int x=s%mo;
while(h[x]!=0 && h[x]!=s)x=(x+1)%mo;
if(h[x]==s)return g[x];else return mo;
}
void pre(int x,int s)
{
if(x>n)
{
sum=0;
for(int i=1;i<=n;i++)
sum=sum+f[i]*z[i-1];
hs(sum,s);
return;
}
add(x);
pre(x+1,s+1);
add(x);
pre(x+1,s);
}
void dg(int x,int s)
{
if(s>=ans)return;
if(x>d)
{
sum=0;
for(int i=1;i<=n;i++)
sum=sum+z[i-1]-f[i]*z[i-1];
ans=min(ans,find(sum)+s);
return;
}
add(x);
dg(x+1,s+1);
add(x);
dg(x+1,s);
}
int main()
{
z[0]=1;
for(int i=1;i<N;i++)
z[i]=z[i-1]*2;
read(n);read(m);
for(int i=1;i<=m;i++)
read(x),read(y),ins(x,y),ins(y,x);
d=n/2;
memset(g,127,sizeof(g));
pre(d+1,0);
memset(f,0,sizeof(f));
ans=2147483647;
dg(1,0);
printf("%d",ans);
}