• 灯 & 树


    这回是两道题一起...

    [USACO09NOV]

    [中山市选2009]树

    题意:给您一些灯,以及一些边。每次改变一盏灯的时候,它相邻的灯也会变。求把灯状态全部转换的最小操作次数。

    解:

    解异或方程组的经典题。

    我们对于灯列一个方程组,如果i对j有影响就令a[j][i] = 1

    然后解出上三角矩阵。

    解出来a[i][i] = 1的地方就是确定的灯。

    0就是可有可无的灯。

    然后我们大暴力搜索可有可无的灯。遇到确定的灯就根据已经搜索的那些来确定。

     1 #include <cstdio>
     2 #include <bitset>
     3 #include <algorithm>
     4 const int N = 40;
     5 
     6 int n, p[N], ans = 0x3f3f3f3f;
     7 std::bitset<N> a[N];
     8 
     9 inline void Gauss() {
    10     for(int i = 1; i < n; i++) {
    11         for(int j = i; j <= n; j++) {
    12             if(a[j][i]) {
    13                 std::swap(a[i], a[j]);
    14                 break;
    15             }
    16         }
    17         if(!a[i][i]) {
    18             continue;
    19         }
    20         for(int j = i + 1; j <= n; j++) {
    21             if(a[j][i]) {
    22                 a[j] ^= a[i];
    23             }
    24         }
    25     }
    26     return;
    27 }
    28 
    29 inline void DFS(int k, int s) {
    30     if(s >= ans) {
    31         return;
    32     }
    33     if(k < 1) {
    34         ans = std::min(ans, s);
    35         return;
    36     }
    37     if(a[k][k]) {
    38         int t = a[k][n + 1];
    39         for(int i = k + 1; i <= n; i++) {
    40             if(a[k][i]) {
    41                 t ^= p[i];
    42             }
    43         }
    44         if(t) { /// need press
    45             p[k] = 1;
    46             DFS(k - 1, s + 1);
    47             p[k] = 0;
    48         }
    49         else {
    50             DFS(k - 1, s);
    51         }
    52     }
    53     else {
    54         DFS(k - 1, s);
    55         p[k] = 1;
    56         DFS(k - 1, s + 1);
    57         p[k] = 0;
    58     }
    59     return;
    60 }
    61 
    62 int main() {
    63     int m;
    64     scanf("%d%d", &n, &m);
    65     for(int i = 1, x, y; i <= m; i++) {
    66         scanf("%d%d", &x, &y);
    67         a[y].set(x);
    68         a[x].set(y);
    69     }
    70 
    71     for(int i = 1; i <= n; i++) {
    72         a[i].set(n + 1);
    73         a[i].set(i);
    74     }
    75 
    76     Gauss();
    77 
    78     DFS(n, 0);
    79 
    80     printf("%d", ans);
    81 
    82     return 0;
    83 }
    AC代码

    一点思考:

    我们能不能把上三角矩阵消成最终的那种结果,然后搜索?这样每次在DFS中确定状态就是O(1)的了。

    我们既然都消完了,能不能直接把 ans += a[i][i] & a[i][n + 1] ?

    事实证明不行...

    随手造了点样例发现过不了...

    不禁开始思考a[i][i] = 0的意义来。

    比如这个最简单的样例:1和2之间有一条边。

    那么消元之后的矩阵是这样的:

    1 1 1

    0 0 0

    这是啥啊.....搞不倒

  • 相关阅读:
    W3C规范
    背景图片调整大小
    comfirm和prompt的区别
    position属性absolute与relative 的区别
    text-decoration和text-indent和text-shadow
    刷新网页跳转锚点
    安卓中location.href或者location.reload 不起作用
    $_SERVER 当前信息
    堆+思维——cf1330E
    树形dp——cf1332F【好题】
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/9415571.html
Copyright © 2020-2023  润新知