zoukankan      html  css  js  c++  java
  • meet in the middle 折半搜索 刷题记录

    复杂度分析

    假设本来是n层,本来复杂度是O(2^n),如果meet in middle那就是n/2层,那复杂度变为O( 2^(n/2) ),跟原来的复杂度相比就相当于开了个方

    比如如果n=40那爆搜2^40肯定T飞,那用meet in middle的话就是2^20就可做了。

    洛谷P2962 [USACO09NOV]灯Lights

    • 灯只有35个,用二进制可以表示所有灯的状态,于是考虑搜索
    • 1表示该灯是亮的,0表示是灭的
    • 把某一个等和与他相邻的灯的位都置1表示该灯位置的开关,用 li 数组表示,按下开关 i 就相当于异或 li[i]
    • map存前半部分能到达的状态下按的最少开关数
    • 先爆搜前半部分,更新map,再爆搜后半部分,看其补集是否存在更新答案
    • 注意前半部分本来就有不需要按灯的状态,所以cnt一开始都是1,最后ans-2即可
    • 基本上抄袭hzwer代码:
       1 #include <bits/stdc++.h>
       2 
       3 using namespace std;
       4 typedef long long ll;
       5 int n, m, flag=1, ans=1e9;
       6 ll x[40], li[40];
       7 ll e=0;
       8 map <ll,int> st;
       9 
      10 void dfs(int now, ll d, int cnt) {
      11     if(now == n/2+1 && flag) {
      12         if( st[d]!=0 ) st[d] = min(st[d], cnt);
      13         else st[d] = cnt;
      14         return;
      15     }
      16     if(now == n+1) {
      17         if( st[e-d]!=0 ) ans = min(ans, st[e-d]+cnt);
      18         return;
      19     }
      20     dfs(now+1, d^li[now], cnt+1); //按下开关
      21     dfs(now+1, d, cnt);
      22 }
      23 
      24 int main(){
      25     cin >> n >> m;
      26     x[1] = 1;
      27     for (int i=2; i<=n; i++) x[i] = x[i-1] << 1 ;
      28     int a, b;
      29     for (int i=0; i<m; i++) {
      30         scanf("%d%d", &a, &b);
      31         li[a] ^= x[b];
      32         li[b] ^= x[a];
      33     }
      34     for (int i=1; i<=n; i++) { li[i] ^= x[i]; e ^= x[i]; }
      35     dfs(1,0,1);
      36     flag = 0;
      37     dfs(n/2+1,0,1);
      38     cout << ans-2 << endl;
      39     return 0;
      40 }
      (>人<;)

    洛谷P4799 [CEOI2015 Day2]世界冰球锦标赛

    • 搜后一半的时候需要知道前一半有多少值小于tmp
    • 把前一半的值用数组保存起来,排个序,upperbound就行了
    • longlong 打成int调了好久,为什么还是会犯这种很傻的错误呢,害
    • 代码:
       1 #include <bits/stdc++.h>
       2 
       3 using namespace std;
       4 typedef long long ll;
       5 ll n,tot,flag=1,ans=0,mid,id=0;
       6 ll c[50];
       7 ll mj[1100000];
       8 
       9 void dfs(ll now,ll s){
      10     if(s>tot) return;
      11     if(now==mid && flag){
      12         mj[++id]=s;
      13         return;
      14     }
      15     if(now==n+1){
      16         ll tmp=tot-s;
      17         ans+=( upper_bound(mj+1, mj+id+1, tmp)-mj-1 );
      18         return;
      19     }
      20     dfs(now+1,s+c[now]);
      21     dfs(now+1,s);
      22 }
      23 
      24 int main(){
      25     cin>>n>>tot;
      26     mid=n/2+1;
      27     for (int i=1; i<=n; i++) scanf("%lld",&c[i]);
      28     dfs(1,0);
      29     sort(mj+1,mj+id+1);
      30     flag=0;
      31     dfs(mid,0);
      32     cout<<ans<<endl;
      33     return 0;
      34 }
      qwq
  • 相关阅读:
    ubuntu下查看环境变量
    ubuntu关闭自动更新、打开 ubuntu 的 apport 崩溃检测报告功能
    Ubuntu 配置AP总结
    ubuntu 12.04亮度无法调节和无法保存屏幕亮度解决办法(echo_brightness)
    Ubuntu 13.04 双显卡安装NVIDIA GT 630M驱动
    Linux下添加硬盘,分区,格式化详解
    Eclipse启动分析
    “蚁族” 的生活方式画像
    Ubuntu下的防火墙
    Ubuntu下的杀毒
  • 原文地址:https://www.cnblogs.com/jiecaoer/p/11707285.html
Copyright © 2011-2022 走看看