hdu 1027 不解释,好多方法,鄙人最近常做搜索,它就做个试验吧!

#include <iostream>
#include <cstdio>

//hdu 1027
using namespace std;

int a[1001];//填充数组
int n,m;
bool isa[1001];//标记数组
int nn[9]={0,1,2,6,24,120,720,5040,40320};//1-9的阶乘

bool search(int i)//填第i个数的搜索式算法,返回bool类型是想加速后面搜索返回
{   
	if(i==n+1)//n+1结束
	{
		for(int i=1;i<=n;i++)
			if(i!=n)printf("%d ",a[i]);
			else printf("%d",a[i]);
			puts("");
		return true;
	}

	if((n-i)>8) //由于10000位在阶乘里不超过8!所以前面n-8可心直接填充
	{
		int j;
		for(j=i;j<=n-8;j++){
			isa[j]=true;a[j]=j;
		} 
		if(search(j))return true; //填完后直接搜索下一层
	}
	else 
	{
		if(m==1&&i==n)//填最后一个元素,不这样会我后面的代码出错
		{
			for(int j=(n-8)>0?(n-8):1;j<=n;j++)//注意j的选法,
				//因前面n-8已经不可能用在后面填充里面了
				if(!isa[j]) 
				{a[i]= j;if(search(n+1))return true;}//
		}
		  int ii=0,k=0;//ii记录m位于哪个阶乘位置,k记录m有多少个这样的阶乘,
		  //即它是从余下的数组里选的第k个最小的数
         for( ii=8;ii>=1;ii--) if(nn[ii]<m) break;//找m的位置

		 bool fun = false;
		 for(;i<n-ii;i++)
		 {                 //如里m的位置前还有数没填,说明可以直接填
			 fun = true;
			 for(int k=1;k<=n;k++)
				 if(!isa[k])
				 { a[i] = k;isa[k]=1;break;}
		 }

		 if(fun)//如果上面填了,直接搜索下一层
			{if(search(i)) return true;}

		 else
		 {
			 while(nn[ii]<m) //有多少个这样的阶乘
			 {m-=nn[ii];k++;}

			 for(int j=(n-8)>0?(n-8):1;j<=n;j++)//选余下数组中第k个没有用的填充一个位置,
				 //再搜索下一层
			 {
				 if(k==0&&!isa[j])
				 {isa[j] = 1;a[i]=j;if(search(i+1)) return true;}
				 else if(!isa[j]) k--;
			 }
		 }
	}
}

int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{   
		memset(isa,0,sizeof(isa));
		search(1);
	}
	return 0;
}

你可能感兴趣的:(hdu 1027 不解释,好多方法,鄙人最近常做搜索,它就做个试验吧!)