zoukankan      html  css  js  c++  java
  • [DFS]排队(间隔排列)-C++

    Description

    小Q是班长。在校运动会上,小Q班要进行队列表演。小Q要选出2*N名同学编队,每人都被编上一个号,每一个从1到N的自然数都被某2名同学佩戴,现在要求将他们排成一列,使两个编号为1的同学中间恰好夹1名同学,两个编号为2的同学中间恰好夹2名同学,……,两个编号为N的同学中间恰好夹N名同学,小Q希望知道这样的排法能否实现。

    Input

    输入文件仅包括一行,即要处理的N。N<=13

    Output

    输出有多少种排列顺序.

    Sample Input

    3

    Sample Output

    2

    先理解一下题目,题目中所述,每一个从1到N的自然数都被某2名同学佩戴,说明共有2N名同学,两个编号为N的同学中间恰好夹N名同学,就可以得到一个排列(以n==3为例):

    在这里插入图片描述
    然后,就可以用DFS搜索了。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,ans=0;
    int flag[100]={0};
    
    void dfs(int dep){
    	
    	if(dep>n){
    		ans++;
    		return ;
    	}
    	for(int i=1;i<=2*n-dep-1;i++){
    		if(!flag[i]&&!flag[i+dep+1]){//考虑当前位置有无其他数,和它的间隔有没有其他数
    			flag[i]=flag[i+dep+1]=1;
    			dfs(dep+1);
    			flag[i]=flag[i+dep+1]=0;
    		}
    	}
    }
    int main(){
    	cin >> n;
    	dfs(1);
    	cout << ans;
    	
    	return 0;
    }
    

    但是,可以发现,当程序运行12或13时,耗时很长,那么就可以想到剪枝优化。

    	if(n%4==1||n%4==2){
    		return ; 
    	}
    

    现在,就可以证明一下这个剪枝的得到。
    设问题的一个解为a1+a2···+an,a1表示1。
    那么可以得到a1+a2+…+an+(a1+1+1)+(a2+2+1)+…+(an+n+1),最后解得4(a1+a2+…+an)=n(3n-1),所以n%41或n%42无解。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,ans=0;
    int flag[100]={0};
    
    void dfs(int dep){
    	
    	if(n%4==1||n%4==2){
    		return ; 
    	}
    	if(dep>n){
    		ans++;
    		return ;
    	}
    	for(int i=1;i<=2*n-dep-1;i++){
    		if(!flag[i]&&!flag[i+dep+1]){
    			flag[i]=flag[i+dep+1]=1;
    			dfs(dep+1);
    			flag[i]=flag[i+dep+1]=0;
    		}
    	}
    }
    int main(){
    	cin >> n;
    	dfs(1);
    	cout << ans;
    	
    	return 0;
    }
    
  • 相关阅读:
    JavaScript框架设计 一、种子模块
    一、微服务架构概述(spring cloud与docker学习)
    C++之socket编程
    原定于6日的维护延期
    网站将于8月5日或6日进行维护
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
  • 原文地址:https://www.cnblogs.com/A-Konnyaku/p/11194168.html
Copyright © 2011-2022 走看看