[HAOI2013] 开关控制

  这题让我知道了一种从来没接触过的酷算法——折半搜索!

  还让我知道了一个大佬——GTH!

  还是一个省的,NOIP D1 T1 爆零都比我考的高......虽然我也只有5分,但我是没推出来,人家推出来了被评测坑了,不能比......

  这年头,OI界这么多女装大佬,而真的女生又这么爷们er么......

  真诚的祝福您进队!

  说实话我不太清楚 O ( n! ) 能过多大的数据。

  首先这题的二进制表示状态也帅的不行,对于我这种位运算渣渣来说,能对着一份状压DP的代码膜...好久......然后陷入深深的绝望。

  回正题。

  所谓折半搜索,即把原来的搜索规模缩小一半,先搜索所给数据的前半部分,并用map将对应状态的值保存下来。

  之后对后半部分数据进行搜索,搜索过程中查询当前状态的补集是否已经在第一次搜索中得到,没有的话就正常搜索,有的话就可以直接将两个状态的函数值直接相加得到一个答案,有效的减少了时间开销。

  超大容量背包也是用的这个原理,不过我懒没做啊,而且COGS上没......

  其实我的理解也只是皮毛,毕竟只这一道题,而且对时间复杂度以及正确性也存在一定的疑问。

  不过还是过了,好像正解是解方程组?我开始也试着推了推,不过并不会解。

  真的不喜欢数学题啊,高斯消元寒假学完也忘得一干二净了。

  。。。。。。

 

// q.c
// mark~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int M=35+7;
int n,m,mid; 
bool f[M][M];
LL aim,ans,w[M];
map<LL,LL> cost;
void dfs1(int x,LL y,LL z) {
	if(y) if(z<cost[y]||!cost[y]) cost[y]=z;
	if(z>ans) return ;
	if(y==aim) { ans=min(ans,z); return ; }
	for(int i=x;i<=mid;i++) dfs1(i+1,y^w[i],z+1);
}
void dfs2(int x,LL y,LL z) {
	if(z>ans) return ;
	if(y==aim) { ans=min(ans,z); return ; }
	LL dy=aim-y;
	if(cost[dy]) { ans=min(ans,z+cost[dy]); return ; }
	for(int i=x;i<=n;i++) dfs2(i+1,y^w[i],z+1);
}
int main() {
	freopen("haoi13t3.in","r",stdin);
	freopen("haoi13t3.out","w",stdout);
	scanf("%d%d",&n,&m);
	aim=((long long)1<<n)-1; 
	ans=n; mid=n/2;
	int a,b;
	for(int i=1;i<=m;i++) {
		scanf("%d%d",&a,&b);
		f[a][b]=f[b][a]=true;
	}
	for(int i=1;i<=n;i++) {
		f[i][i]=1;
		LL x=0;
		for(int j=1;j<=n;j++) if(f[i][j]) x|=(long long)1<<j-1;
		w[i]=x;
	}
	dfs1(1,0,0);
	dfs2(mid+1,0,0);
	printf("%lld\n",ans);
	return 0;
}

 

posted @ 2018-04-15 18:40  qjs12  阅读(111)  评论(0编辑  收藏  举报