BZOJ3682: Phorni 后缀平衡树+线段树
BZOJ2790: [Poi2012]Distance 数学+线性筛

BZOJ1130: [POI2008]POD Subdivision of Kingdom 状压+dfs+恶心题

shinbokuow posted @ Sep 15, 2015 07:10:23 PM in BZOJ with tags 状压 dfs 恶心题 , 1209 阅读

 

题解:

这题做的恶心死我了。。。

简直是要多恶心有多恶心。。。

将我为数不多的信心消磨殆尽。。。

完全照着大爷题解,大家去看大爷题解吧。。。

不过有几点补充:

(1)在$O(\binom{n}{m})$时间内找出所有组合:

我们依次确定每个元素选不选,进行dfs,如果当前已经是一个叶子节点直接返回(剩下的全部选择才刚好$m$个),否则就搞两个分支下去。

这样的话是一棵二叉树,且每一个叶子都是一种方案,于是就是线性的咯。

当然我自己就没这样写了。

(2)如果允许重边的话看起来就没这样容易了?

代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define N 26
int s[N];
int n,m;
int c[1<<13];
int f(int x){
	return c[x&((1<<(n>>1))-1)]+c[x>>(n>>1)];
}
int ans=0x3f3f3f3f,re;
void dfs(int lastnum,int lastpos,int lasts,int lastans){
	if(lastnum==(n>>1)){
		if(ans>lastans){
			ans=lastans;
			re=lasts;
		}
		return;
	}
	for(int i=lastpos+1;i<n;++i)
		dfs(lastnum+1,i,lasts|(1<<i),lastans-f(s[i]&lasts)+f(s[i]&(((1<<n)-1)^lasts)));
}
int main(){
#ifndef ONLINE_JUDGE
	//freopen("tt.in","r",stdin);
#endif
	cin>>n>>m;
	int i,j,a,b;
	while(m--){
		scanf("%d%d",&a,&b);
		--a;
		--b;
		s[a]|=1<<b;
		s[b]|=1<<a;
	}
	for(i=1;i<(1<<(n>>1));++i)
		c[i]=c[i>>1]+(i&1);
	dfs(0,-1,0,0);
	if(~re&1)
		re^=((1<<n)-1);
	for(i=0;i<n;++i)
		if((re>>i)&1)
			printf("%d ",i+1);
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter