for (int s = m; ; s = (s - 1) & m) {
    // 使用子集合 s
    if (s == 0) break;
}
for (int s = m; s < (1<<n); s = (s + 1) | m) {
    // s 是 m 的超集合
}
原題:
https://cses.fi/problemset/task/2129
題意:
有 n 個人與 n 項任務,給定代價矩陣 cost[i][j],每人分到 exactly 一個任務,最小化總成本。
解題思路:
#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n; if(!(cin>>n)) return 0;
    vector<vector<long long>> cost(n, vector<long long>(n));
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin>>cost[i][j];
    const long long INF = (long long)4e18;
    int M = 1<<n;
    vector<long long> dp(M, INF);
    dp[0] = 0;
    for(int mask=0; mask<M; ++mask){
        int i = __builtin_popcount((unsigned)mask); // 已分配的人數
        if(i>=n) continue;
        if(dp[mask] == INF) continue;
        for(int j=0;j<n;j++){
            if(!(mask & (1<<j))){
                int nxt = mask | (1<<j);
                dp[nxt] = min(dp[nxt], dp[mask] + cost[i][j]);
            }
        }
    }
    cout << dp[M-1] << "\n";
    return 0;
}
原題:
https://cses.fi/problemset/task/1653
題意:
每個人重量 w[i],電梯容量 x,希望載完所有人所需最少趟數。
解題思路:
#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n; long long x; 
    if(!(cin>>n>>x)) return 0;
    vector<long long> w(n);
    for(int i=0;i<n;i++) cin>>w[i];
    int M = 1<<n;
    const long long INF = (long long)4e18;
    vector<pair<int,long long>> dp(M, {n+1, INF});
    dp[0] = {1, 0}; // 空集合視為開第一趟、重量 0(常見做法)
    auto better = [](pair<int,long long> a, pair<int,long long> b){
        if(a.first != b.first) return a.first < b.first;
        return a.second < b.second;
    };
    for(int mask=0; mask<M; ++mask){
        auto [r, cur] = dp[mask];
        if(r==n+1) continue;
        for(int i=0;i<n;i++){
            if(!(mask & (1<<i))){
                pair<int,long long> cand;
                if(cur + w[i] <= x) cand = {r, cur + w[i]};
                else cand = {r+1, w[i]};
                int nxt = mask | (1<<i);
                if(better(cand, dp[nxt])) dp[nxt] = cand;
            }
        }
    }
    cout << dp[M-1].first << "\n";
    return 0;
}
原題:
https://leetcode.com/problems/partition-to-k-equal-sum-subsets/description/
題意:把陣列分成 k 個子集合,使每組和相等。
解題思路:
class Solution {
public:
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        long long sum = accumulate(nums.begin(), nums.end(), 0LL);
        if(sum % k) return false;
        int n = nums.size();
        int target = sum / k;
        sort(nums.begin(), nums.end(), greater<int>());
        if(nums[0] > target) return false;
        int M = 1<<n;
        vector<int> dp(M, -1);
        dp[0] = 0;
        for(int mask=0; mask<M; ++mask){
            if(dp[mask] == -1) continue;
            for(int i=0;i<n;i++){
                if(!(mask & (1<<i))){
                    if(dp[mask] + nums[i] <= target){
                        int nxt = mask | (1<<i);
                        int val = (dp[mask] + nums[i]) % target;
                        if(dp[nxt] == -1) dp[nxt] = val;
                        // 可加速:若裝滿一桶(val==0)通常更有利,亦可不覆蓋舊值
                    }
                }
            }
        }
        return dp[M-1] == 0;
    }
};
原題:
https://leetcode.com/problems/matchsticks-to-square/
題意:用一堆火柴是否能組成正方形(四邊等長)。
解題思路:
class Solution {
public:
    bool makesquare(vector<int>& matchsticks) {
        long long sum = accumulate(matchsticks.begin(), matchsticks.end(), 0LL);
        if(sum % 4) return false;
        int target = sum / 4;
        int n = matchsticks.size();
        sort(matchsticks.begin(), matchsticks.end(), greater<int>());
        if(matchsticks[0] > target) return false;
        int M = 1<<n;
        vector<int> dp(M, -1);
        dp[0] = 0;
        for(int mask=0; mask<M; ++mask){
            if(dp[mask] == -1) continue;
            for(int i=0;i<n;i++){
                if(!(mask & (1<<i))){
                    if(dp[mask] + matchsticks[i] <= target){
                        int nxt = mask | (1<<i);
                        int val = (dp[mask] + matchsticks[i]) % target;
                        if(dp[nxt] == -1) dp[nxt] = val;
                    }
                }
            }
        }
        return dp[M-1] == 0;
    }
};