zoukankan      html  css  js  c++  java
  • BZOJ1770:[USACO]lights 燈(高斯消元,DFS)

    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上面的開關。

    Solution

    不能再这么颓了不然真的就要凉透了
    还有这题目为什么是繁体的

    搞死小圆高斯消元好强啊QAQ这个题的做法也好神奇啊
    很容易可以发现,开关的顺序不会影响最终结果

    那么到底应该怎么搞呢?举个栗子
    有3盏灯,其中1和2连接,1和3不连接,那么我们可以列出一个方程
    (1*ans[1])^(1*ans[2])^(0*ans[3])=1
    ans[]表示这个灯有没有按。灯1本身或者和灯1相连的灯系数为1,否则为0
    为什么这么列呢?很容易发现,如果为1的项的异或和为1,那么最后结果肯定是1
    感性理解一下,应该挺好懂的
    以此类推我们可以列出n个这样的方程,然后我们就可以用高斯消元来把这个矩阵消了
    消异或矩阵和消普通矩阵是一样的,只不过是把加减的操作换成异或
     
    消了之后不要记着求答案,因为答案里面可能有自由变元。
    怎么办呢?可以用爆搜替代普通高斯消元的答案回带,
    若当前行的答案固定就算出来,否则的话就枚举0/1记入答案。继续搜下一层。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (50)
     5 using namespace std;
     6 
     7 int n,m,minn=0x7fffffff,u,v;
     8 int f[N][N],ans[N],head[N],num_edge;
     9 
    10 void Gauss()
    11 {
    12     for (int i=1; i<=n; ++i)
    13     {
    14         int num=i;
    15         for (int j=i+1; j<=n; ++j)
    16             if (f[j][i]>f[i][i])
    17                 num=j;
    18         if (num!=i)
    19             for (int j=1; j<=n+1; ++j)
    20                 swap(f[i][j],f[num][j]);
    21         for (int j=i+1; j<=n; ++j)
    22             if (f[j][i])
    23                 for (int k=i; k<=n+1; ++k)
    24                     f[j][k]^=f[i][k];
    25     }
    26 }
    27 
    28 void Dfs(int x,int now)
    29 {
    30     if (now>=minn) return;
    31     if (x==0) {minn=now; return;}
    32     
    33     if (f[x][x])
    34     {
    35         int t=f[x][n+1];
    36         for (int i=x+1; i<=n; ++i) t^=f[x][i]*ans[i];
    37         ans[x]=t;
    38         Dfs(x-1,now+(t==1));
    39     }
    40     else
    41     {
    42         ans[x]=0; Dfs(x-1,now);
    43         ans[x]=1; Dfs(x-1,now+1);
    44     }
    45 }
    46 
    47 int main()
    48 {
    49     scanf("%d%d",&n,&m);
    50     for (int i=1; i<=m; ++i)
    51     {
    52         scanf("%d%d",&u,&v);
    53         f[u][v]=f[v][u]=1;
    54     }
    55     for (int i=1; i<=n; ++i) f[i][n+1]=f[i][i]=1;
    56     Gauss();
    57     Dfs(n,0);
    58     printf("%d",minn);
    59 }
  • 相关阅读:
    PyQt(Python+Qt)学习随笔:containers容器类部件QStackedWidget重要方法介绍
    什么叫工业4.0,这篇接地气的文章终于讲懂了
    怎样 真正认识一个 人
    华为的绩效管理:减人、增 效、加薪
    羽毛球战术
    魔方教程
    员工培养:事前指导,事后纠正
    一把手瞄准哪里,核心竞争力就在哪里
    海尔的五次战略变革
    如何提高基层员工的执行力
  • 原文地址:https://www.cnblogs.com/refun/p/8947070.html
Copyright © 2011-2022 走看看