ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

[DFS]排队(间隔排列)-C++

2019-07-16 13:04:36  阅读:75  来源: 互联网

标签:同学 dfs return int 排队 n% DFS a1 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%4==1或n%4==2无解。

#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;
}


标签:同学,dfs,return,int,排队,n%,DFS,a1,C++

专注分享技术,共同学习,共同进步。

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有