码迷,mamicode.com
首页 > 其他好文 > 详细

解题:POI 2008 Subdivision of Kingdom

时间:2018-10-13 02:20:31      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:int   none   判断   blank   lap   poi   分享   span   pen   

题面

还可以这么搜......学到了(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

 

解题:POI 2008 Subdivision of Kingdom

标签:int   none   判断   blank   lap   poi   分享   span   pen   

原文地址:https://www.cnblogs.com/ydnhaha/p/9781214.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!