• 高斯消元法求解异或方程组: cojs.tk 539.//BZOJ 1770 牛棚的灯


    高斯消元求解异或方程组:

        比较不错的一篇文章:http://blog.sina.com.cn/s/blog_51cea4040100g7hl.html

    cojs.tk  539. 牛棚的灯

    ★★☆   输入文件:lights.in   输出文件:lights.out   简单对比
    时间限制:1 s   内存限制:128 MB

    【问题描述】

    贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了。贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊恐,痛苦与绝望。她希望您能够帮帮她,把所有的灯都给重新开起来!她才能继续快乐地跟她的闺密们继续玩游戏!

    牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常复杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。

    每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开着的时候,这盏灯被关掉;当一盏灯是关着的时候,这盏灯被打开。

    问最少要按下多少个开关,才能把所有的灯都给重新打开。

    数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。

    题目名称:lights

    输入格式:

    *第一行:两个空格隔开的整数:N和M。

    *第二到第M+1行:每一行有两个由空格隔开的整数,表示两盏灯被一条无向边连接在一起。
    没有一条边会出现两次。

    样例输入(文件 lights.in):

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

    输入细节:

    一共有五盏灯。灯1、灯4和灯5都连接着灯2和灯3。

    输出格式:

    第一行:一个单独的整数,表示要把所有的灯都打开时,最少需要按下的开关的数目。

    样例输出(文件 lights.out):

    3

    输出细节:

    按下在灯1、灯4和灯5上面的开关。

    hwzer的代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 #define inf 1000000000
     8 #define ll long long
     9 using namespace std;
    10 inline int read()
    11 {
    12     int x=0,f=1;char ch=getchar();
    13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 int n,m,tot;
    18 int mn=inf;
    19 int f[45][45],ans[45];
    20 void gauss()
    21 {/*一共有n个方程,n个变量*/
    22     for(int i=1;i<=n;i++)
    23     {
    24         int j=i;/*第i行第i列是要向下消元的,如果该行是0,就找一个不是0的一行和他互换后,向下消元,如果j>n,说明所有行的第i列都是0,那就不用消元了*/
    25         while(j<=n&&!f[j][i])j++;
    26         if(j>n)continue;
    27         if(i!=j)for(int k=1;k<=n+1;k++)swap(f[i][k],f[j][k]);/*互换*/
    28         for(int j=i+1;j<=n;j++)/*用第i行向下消元*/
    29             if(i!=j&&f[j][i])/*消元时,只消这一项不是0的方程即可*/
    30                 for(int k=1;k<=n+1;k++)/*消这个方程的时候要把所有的量的都对应相消*/
    31                     f[j][k]^=f[i][k];
    32     }
    33 }
    34 /*,因为,上面只是求出一组解,并不是最小解。
    35 所以,我们需要求出所有解,然后输出最小的那个。
    36 在求倒三角后,有一些m[i][i]==0,这时,我们对x[i]的取值就有两种,0或1。
    37 本身,x[i]的取值对第i行的方程没有任何影响,但它的取值对其他方程有影响,
    38 所以,这里需要枚举x[i]的取值。*/
    39 void dfs(int now)
    40 {/*tot表示按下灯的数目*/
    41     if(tot>=mn)return;/*剪枝,取小操作,一旦大了就不用求了*/
    42     if(!now)/*搜索的终点*/
    43     {
    44         mn=min(mn,tot);
    45         return;
    46     }
    47     if(f[now][now])/*如果now不是自由变元*/
    48     {/*这就是求出当前解ans[now]的过程,利用了性质t=a^b,那么t^b等于a,最后的 f[now][n+1],是由前面的ans[i](f[now][i]不等于0)异或得出的,可以异或回去,求出ans[now] */
    49         int t=f[now][n+1];
    50         for(int i=now+1;i<=n;i++)
    51             if(f[now][i])t^=ans[i];
    52         ans[now]=t;
    53         if(t)tot++;/*如果当前的灯要按下,统计总数*/
    54         dfs(now-1);/*搜索上一盏灯*/
    55         if(t)tot--;/*回溯的过程,为什么可以回溯呢,因为异或方程组会有多组解,即使当前的now灯不按下,求后面的now-1仍然可以有解,说不定还可以更优,所以要回溯*/
    56     }
    57     else /*如果now是自由变元,自由变元取到任何值,最终方程都会有解,就枚举x[now]是0还是1,进行搜索*/
    58     {
    59         ans[now]=0;dfs(now-1);
    60         ans[now]=1;tot++;dfs(now-1);tot--;/*别忘记搜索中的回溯*/
    61     }
    62 }
    63 int main()
    64 {/*f[i][j]表示i--j有边相连,所以是1,其余的是0,在方程组中,*0后结果就没有影响了*/
    65     freopen("lights.in","r",stdin);
    66     freopen("lights.out","w",stdout);
    67     n=read();m=read();
    68     for(int i=1;i<=n;i++)
    69         f[i][i]=1,f[i][n+1]=1;
    70     for(int i=1;i<=m;i++)
    71     {
    72         int x=read(),y=read();
    73         f[x][y]=f[y][x]=1;
    74     }
    75     gauss();dfs(n);/*从n开始搜索,是因为n的变元数目少*/
    76     printf("%d
    ",mn);
    77     fclose(stdin);fclose(stdout);
    78     return 0;
    79 }

    我的代码:

     1 #define N 40
     2 #include<iostream>
     3 using namespace std;
     4 #include<cstdio>
     5 #include<cstring>
     6 int ans[N],f[N][N],x,y,n,m;
     7 int minn=(1<<31)-1,tot=0;
     8 int read()
     9 {
    10     int sum=0,ff=1;char s;
    11     s=getchar();
    12     while(s<'0'||s>'9')
    13     {
    14         if(s=='-') ff=-1;
    15         s=getchar();
    16     }
    17     while('0'<=s&&s<='9')
    18     {
    19         sum=sum*10+s-'0';
    20         s=getchar();
    21     }
    22     return sum*ff;
    23 }
    24 void gauss()
    25 {
    26     for(int i=1;i<=n;++i)
    27     {
    28         int j=i;
    29         while(j<=n&&!f[j][i]) j++;
    30         if(j>n) continue;
    31         if(i!=j)
    32         {
    33             for(int k=1;k<=n+1;++k)
    34             {
    35                 swap(f[i][k],f[j][k]);
    36             }
    37         }
    38         for(int j=i+1;j<=n;++j)
    39           if(f[j][i])
    40           {
    41               for(int k=1;k<=n+1;++k)
    42                 f[j][k]^=f[i][k];
    43           }
    44     }
    45 }
    46 void dfs(int now)
    47 {
    48     if(tot>=minn) return ;
    49     if(!now)
    50     {
    51         minn=min(minn,tot);
    52         return ;
    53     }
    54     if(f[now][now])
    55     {
    56         int t=f[now][n+1];
    57         for(int i=now+1;i<=n;++i)
    58         if(f[now][i]) t^=ans[i];
    59         ans[now]=t;
    60         if(t) tot++;
    61         dfs(now-1);
    62         if(t) tot--;
    63     }
    64     else 
    65     {
    66         ans[now]=1;tot++;dfs(now-1);
    67         ans[now]=0;tot--;dfs(now-1);
    68     }
    69 }
    70 int main()
    71 {
    72 //    freopen("lights.in","r",stdin);
    73 //    freopen("lights.out","w",stdout);
    74     n=read();m=read();
    75     for(int i=1;i<=n;++i)
    76         f[i][i]=f[i][n+1]=1;
    77     for(int i=1;i<=m;++i)
    78     {
    79         x=read();
    80         y=read();
    81         f[x][y]=f[y][x]=1;
    82     }
    83     gauss();
    84     dfs(n);
    85     printf("%d
    ",minn);
    86 //    fclose(stdin);
    87 //    fclose(stdout);
    88     return 0;
    89  } 
  • 相关阅读:
    android 4.0 中出错 java.lang.UnsupportedOperationException
    怎么确定你的CPU是否支持64位虚拟化
    宽度百分比单位的转换公式
    Test SRM Level Three: LargestCircle, Brute Force
    802.11(wifi)的MAC层功能
    zookeeper集群的python代码测试
    mysqldump 命令的使用
    xp硬盘安装Fedora14 过程记录及心得体会(fedora14 live版本680M 和fedora14 DVD版本3.2G的选择)
    ContentProvider的使用
    基于 Java 2 运行时安全模型的线程协作--转
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5551344.html
Copyright © 2020-2023  润新知