zoukankan      html  css  js  c++  java
  • 灯Lights[USACO09NOV]

     题目链接:https://www.luogu.org/problemnew/show/P2962

     

     题解:

      一道高斯消元题,也可以用搜索写。所以我选择搜索。

      可以发现每一个开关最多只用操作一次(因为开关两次等于不动,何必浪费步数呢?),所以我们可以考虑每个开关的状态,一共有2^n次方种情况,复杂度过高。

      我们考虑一下优化。

      我们将每个开关看做二进制下的一位,将每个开关看做一个数(数的值为自己以及该灯所能到达的灯的二进制的亦或和)。我们举个例子:样例中n为5,那么每个点所对应的二进制位为:1-1(1),2-2(10),3-4(100),4-8(1000),5-16(10000)。因为1点能够到达的点为2和3,所以1点所对应的值为6(2^4)。

      我们让一个方案的值为该方案所选的所有点的值的亦或和,那么当一个方案的值为(2^n-1)时,这个方案就是满足条件的。

      其实我们不用枚举所有的方案,用meet in the middle可以使复杂度变为O(sqrt(2^n))。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<vector>
     5 #include<map>
     6 #define LL long long
     7 #define RI register int
     8 using namespace std;
     9 const int INF = 0x7ffffff ;
    10 const int N = 40 ;
    11 
    12 inline int read() {
    13     int k = 0 , f = 1 ; char c = getchar() ;
    14     for( ; !isdigit(c) ; c = getchar())
    15       if(c == '-') f = -1 ;
    16     for( ; isdigit(c) ; c = getchar())
    17       k = k*10 + c-'0' ;
    18     return k*f ;
    19 }
    20 int n, m, lv, ans = INF ; LL hh[N] ; LL tt ; LL p1[N], bin[N] ;
    21 bool flag ;
    22 map<LL,int>p ;  // 开不下2^35的数组,其实最多只有2^18次方个状态,所以用map
    23 
    24 void dfs(int now,LL res,int used) {
    25     if(now > lv) {
    26         if(res == tt) {
    27             ans = min(ans,used) ;
    28         }
    29         else {
    30             if(!flag) {
    31                 int t = p[res] ;
    32                 if(!t || used < t) p[res] = used ;
    33             } else {
    34                 if(p[tt^res]) ans = min(ans,p[tt^res]+used) ;
    35             }
    36         }
    37         return ;
    38     }
    39     dfs(now+1,res^p1[now],used+1) ; dfs(now+1,res,used) ; // 选与不选 
    40 }
    41 
    42 int main() {
    43     n = read(), m = read() ;
    44     bin[0] = 1 ;
    45     for(int i=1;i<=n;i++) bin[i] = bin[i-1]<<1 ;
    46     tt = bin[n] - 1 ;
    47     memset(hh,0,sizeof(hh)) ;
    48     LL x, y ;
    49     for(int i=1;i<=m;i++) {
    50         x = read(), y = read() ;
    51         hh[x] ^= bin[y-1], hh[y] ^= bin[x-1] ;
    52     }
    53     for(int i=1;i<=n;i++) hh[i] ^= bin[i-1] ;
    54     lv = n>>1 ;
    55     for(int i=1;i<=lv;i++) p1[i] = hh[i] ;
    56     dfs(1,0,0) ;  // 搜索前一半 
    57     for(int i=1;i<=n-lv;i++) p1[i] = hh[i+lv] ;
    58     lv = (n+1)>>1 ; flag = 1 ; // flag标记在搜索前半段还是后半段 
    59     dfs(1,0,0) ;  // 搜索后一半 
    60     printf("%d",ans) ;
    61     return 0 ;
    62 }
    View Code
  • 相关阅读:
    Servlet的几种跳转(转)
    Java String.split()用法小结(转)
    表单数据提交的方法
    gedit文本编辑器乱码解决办法
    J-Link烧写bootloader到mini2440的Nor Flash
    虚拟机安装Fedora10系统遇到异常
    linux系统忘记root密码怎么办?
    编译busybox时出错及解决方案
    source insight代码查看器如何自定义添加文件类型
    < Objective-C >文件操作-NSFileHandle
  • 原文地址:https://www.cnblogs.com/zub23333/p/8618661.html
Copyright © 2011-2022 走看看