zoukankan      html  css  js  c++  java
  • 解题:POI 2008 Subdivision of Kingdom

    题面

    还可以这么搜......学到了(PoPoQQQ orz)

    我们最朴素的做法是枚举所有状态(当然可以剪,剪完最终实际状态量也是$C_{26}^{13}$的),然后每次$O(n)$扫一遍判断,大概会T炸,考虑优化

    我们先预处理每个状态中$1$的数目和连边的状态,然后压缩状态初始让一边集合为空,一边集合为全集,这样每次从已有的点的前面$frac{n}{2}$个点中枚举一个加入另一边,就可以边搜边更新边数而不用最后$O(n)$检查了。另一个问题是数组可能非常大,这里我们可以把状态拆成前后两半,然后检查的时候检查两半再拼起来就好了。学了学技巧和思想还是挺好的说......

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int ss[28],cnt[1<<13];
     6 int n,m,t1,t2,ans=2e9,anss,num,half;
     7 int s(int x)
     8 {
     9     return 1<<(x-1);
    10 }
    11 int getst(int x)
    12 {
    13     return cnt[x&half]+cnt[x>>num];
    14 }
    15 void DFS(int last,int noww,int state,int numb)
    16 {
    17     if(noww>n) return ;
    18     if(noww==num)
    19     {
    20         if(numb<ans)
    21             ans=numb,anss=state;
    22         return ;
    23     }
    24     for(int i=last;i<=n;i++)
    25         DFS(i+1,noww+1,state|s(i),numb-getst(state&ss[i])+getst((~state)&ss[i]));
    26 }
    27 int main ()
    28 {
    29     scanf("%d%d",&n,&m);
    30     num=n>>1,half=(1<<num)-1;
    31     for(int i=1;i<=m;i++)
    32     {
    33         scanf("%d%d",&t1,&t2);
    34         ss[t1]|=s(t2),ss[t2]|=s(t1);
    35     }
    36     for(int i=1;i<=half;i++)
    37         cnt[i]=cnt[i>>1]+(i&1);
    38     DFS(1,0,0,0);
    39     for(int i=1;i<=n;i++)
    40         if(anss&s(i)) printf("%d ",i);
    41     return 0;
    42 }
    View Code
  • 相关阅读:
    RramSim2
    DiskSim
    FTL2
    Durable NAND flash memory management
    node系列:全局与本地
    CSS系列:less备忘
    Sql Server 2008:调试
    JavaScript系列:再巩固-原型链
    移动端 :meta标签1万个作用
    Asp.Net:Repeater 详情 备用
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9781214.html
Copyright © 2011-2022 走看看