bzoj 1770 [Usaco2009 Nov]lights&nbs

2019-07-14 00:46发布

Description

貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有 的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐, 痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨 密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之 中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向 這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當 一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。

Input

*第一行:兩個空格隔開的整數:N和M。 *第二到第M+1行:每一行有兩個由空格隔開的整數,表示兩盞燈被一條無向邊連接在一起。 沒有一條邊會出現兩次。

Output

第一行:一個單獨的整數,表示要把所有的燈都打開時,最少需要按下的開關的數目。

Sample Input

5 6
1 2
1 3
4 2
3 4
2 5
5 3

輸入細節:

一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。

Sample Output

3

輸出細節:

按下在燈1、燈4和燈5上面的開關。


陡然发现这题用的繁体字。。。说呢怎么这么黑。。。

嗯、这题是用异或方程。
初始一个n*(n+1)的矩阵。
第i行表示第i盏灯的情况,其中的第j位表示第j盏灯的状态变化是否会对其产生影响。第n+1列表示最终状态与初始状态的异或值(一开是都为1,因为都是从关到开转变了状态)
然后就是果果的高斯消元,我的做法是对于每个a[i,i]把n行都消过去、、不是倒三角。。。如果有唯一解的话终态是一条对角线加一条“虚线”,即第n+1列。
然后进行深搜。枚举每个多解情况的操作。
理论复杂度是2^n。。。不过这个的状态树枯枝败叶各种多啊。。。随便减下都只剩下差不多个树干。。。。
在每层深搜之前判断当前解是否小于当前最优解,否则退出。。。
原来超时的20ms水过。。。


AC CODE
program bzoj_1770;
var a:array[1..40,1..40] of longint;
    ans,tot,n,m:longint;
//===================================================================
procedure init;
var i,x,y:longint;
begin
  readln(n,m);
  for i:=1 to n do a[i,i]:=1;
  for i:=1 to n do a[i,n+1]:=1;
  for i:=1 to m do
  begin
    readln(x,y);
    a[y,x]:=1; a[x,y]:=1;
  end; m:=n+1;
end;
//===================================================================
procedure change(x:longint);
var i,j,tt:longint;
begin
  for i:=x+1 to n do
    if a[i,x]<>0 then
    begin
      for j:=1 to m do
      begin
        tt:=a[x,j]; a[x,j]:=a[i,j]; a[i,j]:=tt;
      end; exit;
    end;
end;
//===================================================================
procedure xiaoyuan;
var i,j,k:longint;
begin
  for i:=1 to n do
  begin
    if a[i,i]=0 then change(i);
    if a[i,i]=0 then continue;
    for j:=1 to n do
    begin
      if j=i then continue;
      if a[j,i]=0 then continue;
      for k:=i to m do
        a[j,k]:=a[j,k] xor a[i,k];
    end;
  end;
end;
//===================================================================
procedure dfs(now:longint);
var i:longint;
begin
  if tot>ans then exit;  //加了这一句就过了、、
  if now=0 then
  begin
    if tot
    exit;
  end;
  if a[now,now]=1 then
  begin
    if a[now,m]=1 then inc(tot);
    dfs(now-1);
    if a[now,m]=1 then dec(tot);
  end else
  begin
    if a[now,m]=1 then exit;
    dfs(now-1);
    for i:=now-1 downto 1 do
      if a[i,now]=1 then a[i,m]:=a[i,m] xor 1;
    inc(tot); dfs(now-1); dec(tot);
    for i:=now-1 downto 1 do
      if a[i,now]=1 then a[i,m]:=a[i,m] xor 1;
  end;
end;
//===================================================================
begin
  assign(input,'1.in'); reset(input);
  init;
  xiaoyuan;
  ans:=maxlongint;
  tot:=0; dfs(n);
  writeln(ans);
end.