JZOJ1321 灯
Description
贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了。贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊恐,痛苦与绝望。她希望您能够帮帮她,把所有的灯都给重新开起来!她才能继续快乐地跟她的闺密们继续玩游戏!
牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常复杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。
每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开着的时候,这盏灯被关掉;当一盏灯是关着的时候,这盏灯被打开。
问最少要按下多少个开关,才能把所有的灯都给重新打开。
数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。
牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常复杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。
每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开着的时候,这盏灯被关掉;当一盏灯是关着的时候,这盏灯被打开。
问最少要按下多少个开关,才能把所有的灯都给重新打开。
数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。
Input
第一行:两个空格隔开的整数:N和M。
第二到第M+1行:每一行有两个由空格隔开的整数,表示两盏灯被一条无向边连接在一起。没有一条边会出现两次。
第二到第M+1行:每一行有两个由空格隔开的整数,表示两盏灯被一条无向边连接在一起。没有一条边会出现两次。
Output
第一行:一个单独的整数,表示要把所有的灯都打开时,最少需要按下的开关的数目。
Sample Input
5 6 1 2 1 3 4 2 3 4 2 5 5 3
Sample Output
3
Hint
【样例说明】
一共有五盏灯。灯1、灯4和灯5都连接着灯2和灯3。按下在灯1、灯4和灯5上面的开关。
一共有五盏灯。灯1、灯4和灯5都连接着灯2和灯3。按下在灯1、灯4和灯5上面的开关。
Solution
这题也可以写高斯消元,这里是双向搜索。
先dfs前半部分,用hash储存,再dfs后半部分。
1 #include<cstdio> 2 #define N 1000007 3 using namespace std; 4 int g[N],sum,mi,l,r,b[50][50],n,m; 5 long long t[N],s[40],tt[40]; 6 bool e[50],f[50]; 7 int min(int x,int y) 8 { 9 if (x>y) return y; 10 return x; 11 } 12 int hash(long long x) 13 { 14 int z=x%N; 15 while (t[z]!=0&&t[z]!=x) 16 z=(z+1)%N; 17 return z; 18 } 19 int dfs(int x) 20 { 21 if (x>l) 22 { 23 int p=0; 24 for (int i=1;i<=n;i++) 25 f[i]=false; 26 for (int i=1;i<=l;i++) 27 if (e[i]) 28 { 29 f[i]=not f[i]; 30 for (int j=1;j<=b[i][0];j++) 31 f[b[i][j]]=not f[b[i][j]]; 32 p++; 33 } 34 long long num=0; 35 for (int i=1;i<=n;i++) 36 if (f[i]) num+=s[i]; 37 int k=hash(num); 38 if (t[k]==0) g[k]=p; 39 else g[k]=min(g[k],p); 40 t[k]=num; 41 return 0; 42 } 43 e[x]=true; 44 dfs(x+1); 45 e[x]=false; 46 dfs(x+1); 47 } 48 int dfs1(int x) 49 { 50 if (x>r) 51 { 52 int p=0; 53 for (int i=1;i<=n;i++) 54 f[i]=false; 55 for (int i=l+1;i<=n;i++) 56 if (e[i]) 57 { 58 f[i]=not f[i]; 59 for (int j=1;j<=b[i][0];j++) 60 f[b[i][j]]=not f[b[i][j]]; 61 p++; 62 } 63 long long num=0; 64 for (int i=1;i<=n;i++) 65 if (f[i]) num+=s[i]; 66 int k=hash(s[n]*2-1-num); 67 if (t[k]!=0) 68 mi=min(p+g[k],mi); 69 return 0; 70 } 71 e[l+x]=true; 72 dfs1(x+1); 73 e[l+x]=false; 74 dfs1(x+1); 75 } 76 int ss(int x,int z) 77 { 78 if (z==0) 79 { 80 if (x<mi) 81 mi=x; 82 return 0; 83 } 84 if (x>=mi||x>3) 85 return 0; 86 for (int i=1;i<=n;i++) 87 if (tt[i]) 88 { 89 tt[i]=false; 90 int zz=z; 91 if (f[i]) 92 zz++; 93 else zz--; 94 f[i]=not f[i]; 95 for (int j=1;j<=b[i][0];j++) 96 { 97 if (f[b[i][j]]) 98 zz++; 99 else zz--; 100 f[b[i][j]]=not f[b[i][j]]; 101 } 102 ss(x+1,zz); 103 f[i]=not f[i]; 104 for (int j=1;j<=b[i][0];j++) 105 f[b[i][j]]=not f[b[i][j]]; 106 tt[i]=true; 107 } 108 } 109 int main() 110 { 111 scanf("%d%d",&n,&m); 112 for (int i=1;i<=m;i++) 113 { 114 int x,y; 115 scanf("%d%d",&x,&y); 116 b[x][++b[x][0]]=y; 117 b[y][++b[y][0]]=x; 118 } 119 l=n/2,r=n-l; 120 s[1]=1; 121 for (int i=1;i<=n;i++) 122 { 123 f[i]=false; 124 tt[i]=true; 125 } 126 mi=0xffffff; 127 ss(0,n); 128 for (int i=2;i<=n;i++) 129 s[i]=s[i-1]*2; 130 if (mi!=0) 131 { 132 dfs(1); 133 dfs1(1); 134 } 135 printf("%d",mi); 136 }