BZOJ 1770: [Usaco2009 Nov]lights 燈

Posted You Siki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1770: [Usaco2009 Nov]lights 燈相关的知识,希望对你有一定的参考价值。

1770: [Usaco2009 Nov]lights 燈

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 762  Solved: 368
[Submit][Status][Discuss]

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

HINT

 

Source

[Submit][Status][Discuss]

 

网上的方法大多是高斯消元解异或方程,对于自由元DFS枚举选还是不选;后来看到Monster_Yi神犇和SD_le神犇的双端搜索,觉得也不错。

 

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int MAXN = 105;
 6 
 7 int N, M, G[MAXN][MAXN], ANS, TMP[MAXN];
 8 
 9 void READ(void)
10 {
11     scanf("%d%d", &N, &M);
12     
13     for (int i = 1; i <= N; ++i)
14         G[i][i] = G[i][N + 1] = true;
15     
16     for (int i = 1, x, y; i <= M; ++i)
17     {
18         scanf("%d%d", &x, &y);
19         G[x][y] = G[y][x] = true; 
20     }
21 }
22 
23 void GAUSS(void)
24 {
25     for (int i = 1, j, k; i <= N; ++i)
26     {
27         for (j = i; j <= N && !G[j][i]; ++j);
28         
29         if (j <= N)
30         {
31             if (i != j)
32             {
33                 for (k = 1; k <= N + 1; ++k)
34                     swap(G[i][k], G[j][k]); 
35             }
36             if (G[i][i])
37             {
38                 for (j = 1; j <= N; ++j)
39                     if (i != j && G[j][i])
40                         for (k = 1; k <= N + 1; ++k)
41                             G[j][k] ^= G[i][k];
42             }
43         }
44     }
45 }
46 
47 void DFSANS(int t, int cnt)
48 {
49     if (cnt >= ANS)
50         return;
51     if (t == 0)
52         ANS = min(ANS, cnt);
53     else
54     {
55         if (G[t][t])
56         {
57             TMP[t] = G[t][N + 1];
58             for (int i = N; i > t; --i)
59                 if (G[t][i])TMP[t] ^= TMP[i];
60             DFSANS(t - 1, cnt + TMP[t]);
61         }
62         else
63         {
64             TMP[t] = 0; DFSANS(t - 1, cnt);
65             TMP[t] = 1; DFSANS(t - 1, cnt + 1);
66         }
67     }
68 }
69 
70 void PUTANS(void)
71 {
72     ANS = 2e9;
73     DFSANS(N, 0);
74     printf("%d\\n", ANS);
75 }
76 
77 signed main(void)
78 {
79     READ();    
80     GAUSS();
81     PUTANS();
82 }
高斯消元+DFS枚举

 

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long LL;
 6 
 7 const int N = 40;
 8 const int M = 2000;
 9 
10 int n, m;
11 
12 int tot;
13 int hd[N];
14 int to[M];
15 int nt[M];
16 
17 int ans;
18 
19 map<LL, int> MAP;
20 
21 void insert(LL bit, int cost)
22 {
23     if (MAP.count(bit))
24         MAP[bit] = min(MAP[bit], cost);
25     else
26         MAP[bit] = cost;
27 }
28 
29 void DFS1(int t, LL bit, int cost)
30 {
31     if (t > n / 2)
32     { insert(bit, cost); return; }
33     
34     DFS1(t + 1, bit, cost);
35     
36     bit ^= (1LL << (t - 1));
37     
38     for (int i = hd[t]; ~i; i = nt[i])
39         bit ^= (1LL << (to[i] - 1));
40         
41     DFS1(t + 1, bit, cost + 1);
42 }
43 
44 int query(LL bit)
45 {
46     if (MAP.count(bit))
47         return MAP[bit];
48     else
49         return -1;
50 }
51 
52 void DFS2(int t, LL bit, int cost)
53 {
54     if (t > n)
55     {
56         int ret = query(((1LL << n) - 1) ^ bit);
57         if (ret != -1)ans = min(ans, cost + ret);
58         return;
59     }
60     
61     DFS2(t + 1, bit, cost);
62     
63     bit ^= (1LL << (t - 1));
64     
65     for (int i = hd[t]; ~i; i = nt[i])
66         bit ^= (1LL << (to[i] - 1));
67         
68     DFS2(t + 1, bit, cost + 1);
69 }
70 
71 signed main(void)
72 {
73     scanf("%d%d", &n, &m);
74     
75     memset(hd, -1, sizeof(hd));
76     
77     for (int i = 1; i <= m; ++i)
78     {
79         int x, y; scanf("%d%d", &x, &y);
80         nt[tot] = hd[x]; to[tot] = y; hd[x] = tot++;
81         nt[tot] = hd[y]; to[tot] = x; hd[y] = tot++;
82     }
83     
84     ans = 2e9;
85     DFS1(1, 0LL, 0);
86     DFS2(n / 2 + 1, 0LL, 0);
87     
88     printf("%d\\n", ans);
89 }
双端搜索

 

 

 

@Author: YouSiki

 

以上是关于BZOJ 1770: [Usaco2009 Nov]lights 燈的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1770: [Usaco2009 Nov]lights 燈

bzoj 1770 [Usaco2009 Nov]lights 燈 meet in the middle

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

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

bzoj2017[Usaco2009 Nov]硬币游戏*

BZOJ 2017: [Usaco2009 Nov]硬币游戏(A Coin Game)