题意

给定一个无向图,初始状态所有点均为黑,如果更改一个点,那么它和与它相邻的点全部会被更改。一个点被更改当它的颜色与之前相反。

题解

第一道Gauss消元题。所谓gauss消元,就是使用初等行列式变换把原矩阵转化为上三角矩阵然后回套求解。

给定一个矩阵以后,我们考察每一个变量,找到它的系数最大的一行,然后根据这一行去消除其他的行。具体地代码如下面所示。

  1. double a[N][N]
  2. void Gauss(){
  3. for(int i=1;i<=n;i++){
  4. int r=i;
  5. for(int j=i+1;j<=n;j++)
  6. if(abs(a[j][i])>abs(a[r][i])) r=j;
  7. if(r!=i) for(int j=1;j<=n+1;j++) swap(a[i][j],a[r][j]);
  8. for(int j=i+1;j<=n;j++){
  9. double t=a[j][i]/a[i][i];
  10. for(int k=i;k<=n+1;k++) a[j][k]-=a[i][k]*t;
  11. }
  12. }
  13. for(int i=n;i>=1;i--){
  14. for(int j=n;j>i;j--) a[i][n+1]-=a[j][n+1]*a[i][j];
  15. a[i][n+1]/=a[i][i];
  16. }
  17. }

对于xor运算,我们可以使用同样的方法消元。

另外,xor的话可以使用bitset压位以加速求解。

代码(附有详细注释)

  1. #include <algorithm>
  2. #include <cstdio>
  3. const int maxn = 45;
  4. int a[maxn][maxn], b[maxn];
  5. int n, m, tot, mn = 0x3f3f3f;
  6. void gauss() {
  7. for (int i = 1; i <= n; i++) { //依次考察每一个未知数
  8. int j = i; //开始选中第i行
  9. while (j <= n && !a[j][i]) //选中系数最大的一行(减小精度误差)
  10. j++;
  11. if (j > n)
  12. continue;
  13. if (i != j)
  14. for (int k = 1; k <= n + 1; k++) //交换两行,使得第i行成为最大系数
  15. std::swap(a[j][k], a[i][k]);
  16. for (int j = 1; j <= n;
  17. j++) // gauss消元核心代码:使用第i行消除所有行的第i个未知数
  18. if (i != j && a[j][i]) //以此来形成一个上三角矩阵,为之后的消元作准备
  19. for (int k = 1; k <= n + 1; k++)
  20. a[j][k] ^=
  21. a[i][k]; //如果是普通的线性方程组,这里需要使用别的方法把系数置零
  22. }
  23. }
  24. void dfs(int now) { //由于gauss消元后有一些自由元,我们需要进行最优解暴力搜索
  25. if (tot >= mn)
  26. return;
  27. if (!now) {
  28. mn = std::min(mn, tot);
  29. return;
  30. }
  31. if (a[now][now]) { //确定的情况
  32. int t = a[now][n + 1];
  33. for (int i = now + 1; i <= n; i++)
  34. if (a[now][i])
  35. t ^= b[i]; //由于是上三角矩阵,所以逆向消元
  36. b[now] = t;
  37. if (t)
  38. tot++;
  39. dfs(now - 1);
  40. if (t)
  41. tot--; //回溯
  42. } else { //自由元的情况,随意确定
  43. b[now] = 0;
  44. dfs(now - 1);
  45. b[now] = 1;
  46. tot++;
  47. dfs(now - 1);
  48. tot--;
  49. }
  50. }
  51. int main() {
  52. #ifdef D
  53. freopen("input", "r", stdin);
  54. #endif
  55. scanf("%d %d", &n, &m);
  56. for (int i = 1; i <= n; i++)
  57. a[i][i] = 1, a[i][n + 1] = 1;
  58. for (int i = 1; i <= m; i++) {
  59. int x, y;
  60. scanf("%d %d", &x, &y);
  61. a[x][y] = a[y][x] = 1;
  62. }
  63. gauss(); //判定是否无解:系数矩阵全0,常数矩阵不全为0
  64. dfs(n);
  65. printf("%d\n", mn);
  66. return 0;
  67. }

附:如何使用bitset

首先,声明bitset:

  1. #include <bitset>
  2. using std::bitset;

初始化:

  1. bitset<n> b;
  2. bitset<n> b(unsigned long u);

上述语句声明了一个n位全部为0的bitset,第二个语句用一个unsigned long long变量去初始化bitset。

bitset的更多操作:

  1. b1 = b2 & b3;//按位与
  2. b1 = b2 | b3;//按位或
  3. b1 = b2 ^ b3;//按位异或
  4. b1 = ~b2;//按位补
  5. b1 = b2 << 3;//移位

[bzoj1770][Usaco2009 Nov]lights 燈——Gauss消元法的更多相关文章

  1. bzoj1770: [Usaco2009 Nov]lights 燈(折半搜索)

    1770: [Usaco2009 Nov]lights 燈 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1153  Solved: 564[Submi ...

  2. bzoj千题计划187:bzoj1770: [Usaco2009 Nov]lights 燈 (高斯消元解异或方程组+枚举自由元)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1770 a[i][j] 表示i对j有影响 高斯消元解异或方程组 然后dfs枚举自由元确定最优解 #in ...

  3. BZOJ1770 : [Usaco2009 Nov]lights 燈

    设$f[i]$表示$i$点按下开关后会影响到的点的集合,用二进制表示. 不妨设$n$为偶数,令$m=\frac{n}{2}$,对于前一半暴力$2^m$搜索所有方案,用map维护每种集合的最小代价. 对 ...

  4. 【dfs】【高斯消元】【异或方程组】bzoj1770 [Usaco2009 Nov]lights 燈 / bzoj2466 [中山市选2009]树

    经典的开关灯问题. 高斯消元后矩阵对角线B[i][i]若是0,则第i个未知数是自由元(S个),它们可以任意取值,而让非自由元顺应它们,得到2S组解. 枚举自由元取0/1,最终得到最优解. 不知为何正着 ...

  5. BZOJ 1770: [Usaco2009 Nov]lights 燈( 高斯消元 )

    高斯消元解xor方程组...暴搜自由元+最优性剪枝 -------------------------------------------------------------------------- ...

  6. 【高斯消元】BZOJ 1770: [Usaco2009 Nov]lights 燈

    Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望. ...

  7. BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]

    题意: 经典灯问题,求最少次数 本题数据不水,必须要暴搜自由元的取值啦 想了好久 然而我看到网上的程序都没有用记录now的做法,那样做遇到自由元应该可能会丢解吧...? 我的做法是把自由元保存下来,枚 ...

  8. 【BZOJ 1770 】 [Usaco2009 Nov]lights 燈 dfs+异或方程组

    这道题明显是异或方程组,然而解不一定唯一他要的是众多解中解为1的数的最小值,这个时候我们就需要dfs了我们dfs的时候就是枚举其有不确定解的数上选0或1从而推知其他解,由于我们dfs的时候先0后1,虽 ...

  9. 【BZOJ】1770 [Usaco2009 Nov]lights 燈

    [算法]高斯消元-异或方程组 [题解]良心简中题意 首先开关顺序没有意义. 然后就是每个点选或不选使得最后得到全部灯开启. 也就是我们需要一种确定的方案,这种方案使每盏灯都是开启的. 异或中1可以完美 ...

随机推荐

  1. 为什么说Objective-C是一门动态的语言?

    object-c类的类型和数据变量的类型都是在运行是确定的,而不是在编译时确定.例如:多态特性,我们可以使用父类对象来指向子类对象,并且可以用来调用子类的方法.运行时(runtime)特性,我们可以动 ...

  2. parity的使用

    parity --chain dev --port 8045 ps aux | grep "parity" ps -elf | grep "pari"

  3. python之time和os模块

    1.time.time()获得的是一个时间戳,距离1970年以来多少秒 2.time.strftime(),按固定格式设置时间 import time print(time.localtime())# ...

  4. Linux arm64内核启动

    原创翻译,转载请注明出处. arm64的异常模型由一组异常级别(EL0-EL3)组成.EL0,EL1有安全模式和非安全模式的区别.EL2是虚拟机管理级别并且只有非安全模式.EL3是最高优先级并且只存在 ...

  5. 浅谈c语言和c++中struct的区别

    今天做二叉树的时候,发现利用结构体有点乱,不知道怎么回事,我之前知道c语言中声明一个结构体变量时需要通过 struct 结构体名 变量名,而在c++中,可以不要struct,由于可以利用typedef ...

  6. PAT java大数 A+B和C

    题目描述: 给定区间[-, ]内的3个整数A.B和C,请判断A+B是否大于C. 输入格式: 输入第1行给出正整数T(<=),是测试用例的个数.随后给出T组测试用例,每组占一行,顺序给出A.B和C ...

  7. lintcode-118-不同的子序列

    118-不同的子序列 给出字符串S和字符串T,计算S的不同的子序列中T出现的个数. 子序列字符串是原始字符串通过删除一些(或零个)产生的一个新的字符串,并且对剩下的字符的相对位置没有影响.(比如,&q ...

  8. PAT 1045 快速排序

    https://pintia.cn/problem-sets/994805260223102976/problems/994805278589960192 著名的快速排序算法里有一个经典的划分过程:我 ...

  9. windows下Memcached 架设及java应用(转)

    1 Memcache是什么 Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力. 它可 ...

  10. Bootstrap中轮播图

    Bootstrap中轮播图插件叫作Carousel,为了清晰的表明每个标签在这里是什么意思,我把解释写在了下面的代码中. <!-- 以下容器就是整个轮播图组件的整体, 注意该盒子必须加上 cla ...