力扣 526. 优美的排列 回溯 状压dp

https://leetcode-cn.com/problems/beautiful-arrangement/
力扣 526. 优美的排列 回溯 状压dp_第1张图片
思路一:还就内个暴力回溯。究极暴力的解法,枚举所有可能性,加上最简单的剪枝即可。

class Solution {
public:
    int countArrangement(int n) {
        vector<bool> vis(n+1);
        int ans=0;
        function<void(int)> dfs=[&](int idx) -> void 
        {
            if(idx==n+1)
            {
                ++ans;
                return;
            }
            for(int i=1;i<=n;i++)
            {
                if(vis[i]||(i%idx!=0&&idx%i!=0))
                    continue;
                vis[i]=1;
                dfs(idx+1);
                vis[i]=0;        
            }
        };
        dfs(1);
        return ans;
    }
};

思路二:依然是回溯,不过可以预处理出每个位置的待选元素,这样不用暴力遍历 n n n个数选择了。

class Solution {
public:
    int countArrangement(int n) {
        vector<bool> vis(n+1);
        vector<vector<int>> nums(n+1);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(j%i==0||i%j==0)
                    nums[i].push_back(j);
            }
        }
        int ans=0;
        function<void(int)> dfs=[&](int idx) -> void 
        {
            if(idx==n+1)
            {
                ++ans;
                return;
            }
            for(int ele:nums[idx])
            {
                if(!vis[ele])
                {
                    vis[ele]=1;
                    dfs(idx+1);
                    vis[ele]=0;
                }
            }
        };
        dfs(1);
        return ans;
    }
};

思路三:状压dp,如果选取了数字 i i i,那么可以令 s t a t e = s t a t e ∣ 2 i state=state|2^i state=state2i,我们用 d p i dp_i dpi表示选择的数字的二进制状态为 i i i的情况下的方案数,那么当前选择的数字总数就等于 i i i二进制表示1的个数,设为 c n t cnt cnt,接下来可以枚举要放在第 c n t cnt cnt位上的数字 j j j,需要满足 i & & 2 j = 2 j i\&\&2^j=2^j i&&2j=2j j % c n t = 0 ∣ ∣ c n t % j = 0 j\%cnt=0||cnt\%j=0 j%cnt=0cnt%j=0,显然有 d p i = d p i + d p i   x o r   2 j dp_i=dp_i+dp_{i\ xor\ 2^j} dpi=dpi+dpi xor 2j

class Solution {
public:
    int countArrangement(int n) {
        int times=1<<n;
        vector<int> dp(times);
        dp[0]=1;
        for(int i=1;i<times;i++)
        {
            int cnt=__builtin_popcount(i);
            for(int j=0;j<n;j++)
            {
                if(i&(1<<j)&&(cnt%(j+1)==0||(j+1)%cnt==0))
                    dp[i]+=dp[i^(1<<j)];
            }
        }
        return dp[times-1];
    }
};

你可能感兴趣的:(力扣,状压dp,回溯)