状压dp一些题目

dp-bitmasks 在中国叫做 状压dp

https://usaco.guide/gold/dp-bitmasks?lang=cpp


题目

https://cses.fi/problemset/task/1690/



#include <bits/stdc++.h>
using namespace std;
 
const int MOD = 1000000007;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;
    
    // 用邻接矩阵保存图的信息,graph[i][j]为true表示存在从城市 i 到城市 j 的单向航班
    vector<vector<bool>> graph(n, vector<bool>(n, false));
    for (int i = 0; i < m; i++){
        int a, b;
        cin >> a >> b;
        // 注意将城市编号从1调整到0(0-based下标)
        graph[a - 1][b - 1] = true;
    }
    
    // dp[mask][i] 表示状态为 mask(一个二进制掩码,表示已经访问的城市集合),且当前所在城市为 i 的路线数
    // 初始状态为只访问了起点城市 1(下标 0),即 mask = 1<<0
    vector<vector<int>> dp(1 << n, vector<int>(n, 0));
    dp[1 << 0][0] = 1;
    
    // 枚举所有的状态(掩码)
    for (int mask = 0; mask < (1 << n); mask++){
        for (int i = 0; i < n; i++){
            // 如果当前状态 mask 下,不在城市 i 的方案数为 0,则跳过
            if(dp[mask][i] == 0) continue;
            // 尝试从城市 i 飞往任意未访问过的城市 j
            for (int j = 0; j < n; j++){
                // 如果城市 j 未访问且存在从 i 到 j 的航班
                if (!(mask & (1 << j)) && graph[i][j]) {
                    int nextMask = mask | (1 << j);
                    dp[nextMask][j] = (dp[nextMask][j] + dp[mask][i]) % MOD;
                }
            }
        }
    }
    
    // 最终答案为所有城市均已访问且终点为城市 n(下标 n-1)的方案数
    cout << dp[(1 << n) - 1][n - 1] << "\n";
    
    return 0;
}
说明
  1. 图的存储
    采用邻接矩阵 graph 存储城市之间的航班信息。由于城市数较小(n ≤ 20),使用邻接矩阵可以方便判断两城市间是否存在航班。

  2. 状态定义
    定义 dp[mask][i] 表示访问状态为 mask、当前位于城市 i 时的方案数。mask 是一个整数,其二进制位表示对应城市是否已经被访问。例如:如果 n=4,则状态 mask = 1011 表示访问了城市 1、2、4(注意下标从0开始)。

  3. 状态转移
    对于每个状态 mask 和当前城市 i,尝试从 i 出发飞到所有未访问的城市 j(即 mask 的第 j 位为 0 且 graph[i][j] 为 true),更新新的状态 mask | (1<<j) 的方案数。

  4. 初始化和答案
    初始状态为只访问起点城市 1,即 dp[1<<0][0]=1。最终要求的答案为所有城市均访问到(即 mask=(1<<n)-1)并且路径终点为城市 n(下标 n-1)的方案数。

这样实现的复杂度为 O(2^n * n^2),对于 n ≤ 20 是可行的。


https://www.cnblogs.com/TSZ-think/category/2013353.html


posted @ 2025-04-14 14:26  katago  阅读(6)  评论(0)    收藏  举报