您的位置:首页 > 其它

【bzoj3990】 SDOI2015排序 dfs搜索+剪枝

2015-07-27 16:37 375 查看
航爷出的题果然太耗脑子了,看完gty大哥的题解才会做。首先有一个结论,操作序列的顺序不影响最终结果,所以我们搜出一种合法的操作组合之后乘以步骤数的阶乘就可以了。然后我们发现,从小到大搜索,当第i次操作完成后,每一个2^i的段必须变成有序的,而且每次操作只允许有4个顺序不同的,这样一交换才可能变成有序。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 10010

using namespace std;

int n;
int a[maxn];
long long c[13];
long long ans;

void swap(int i,int j,int len)
{
	for (int k=1;k<=len;k++) swap(a[i+k-1],a[j+k-1]);
}

bool check(int k)
{
	for (int i=1;i<=(1<<(n-k));i++)
	  if (a[(i-1)*(1<<k)+1]+(1<<(k-1))!=a[(i-1)*(1<<k)+1+(1<<(k-1))]) return 0;
	return 1;
}

void dfs(int now,int num)
{
	if (now && !check(now)) return;
	if (now==n) {ans+=c[num];return;}
	dfs(now+1,num);
	int tmp[5],tot=0;
	for (int i=1;i<=(1<<(n-(now+1)+1));i+=2)
	  if (a[i*(1<<now)+1]!=a[(i-1)*(1<<now)+1]+(1<<now))
	  {
	      if (tot==4) return;
	        else tmp[++tot]=i,tmp[++tot]=i+1;
	  }
	if (!tot)  return;
	for (int i=1;i<tot;i++)
	  for (int j=i+1;j<=tot;j++)
	    {
	    	swap((1<<now)*(tmp[i]-1)+1,(1<<now)*(tmp[j]-1)+1,(1<<now));
	    	dfs(now+1,num+1);
	    	swap((1<<now)*(tmp[i]-1)+1,(1<<now)*(tmp[j]-1)+1,(1<<now));
	    }
}

int main()
{
	c[0]=1;
	for (int i=1;i<=12;i++) c[i]=c[i-1]*i;
	scanf("%d",&n);
	for (int i=1;i<=(1<<n);i++) scanf("%d",&a[i]);
	dfs(0,0);
	printf("%lld\n",ans);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: