zoukankan      html  css  js  c++  java
  • dp-状压dp

    https://www.bilibili.com/video/BV1Z4411x7Kw?from=search&seid=13855865082722302053

    状压介绍:

    状态表示:

     转移方程:i是当前节点,j是下一步要走的节点

     子集枚举:

    核心代码:1。由当前枚举未知

    首先枚举状态,枚举S中包含的节点:枚举i能去的节点

     2.由已知枚举当前

    枚举状态S:S ^ (1 << i) 表示去掉i节点

    5435. 并行课程 II

    yxc代码

     const int INF = 1000;
        vector<int> f;
    
        int minNumberOfSemesters(int n, vector<vector<int>>& edges, int k) {
            f = vector<int>(1 << n, INF);//dp数组
            for (auto& e: edges) e[0] --, e[1] -- ;
            f[0] = 0;// 还没选任何课
            for (int i = 0; i < 1 << n; i ++ ) {//遍历所有状态
                vector<bool> st(n);// 求当前可以选的课有哪些
                for (auto& e: edges) {
                    int x = e[0], y = e[1];
                    if (!(i >> x & 1)) //如果x没有修过
                        st[y] = true;//y有些先修课没被修过
                }
                int state = 0;//state的二进制位表示可以修的课程
                for (int j = 0; j < n; j ++ )
                    if (!st[j] && !(i >> j & 1))// j所有先修课修过,并且j还没有被修
                        state += 1 << j;//则修课程j
                
                dfs(n, k, i, state, 0,0);//i的状态转移
            }
    
            return f[(1 << n) - 1];//返回全部修过时的最短
        }
        //state中选出k个元素来更新
        void dfs(int n, int k, int i, int state, int now, int start) {
            //参数 i 是当前状态,state是可以选的状态, now 是当前已选的状态, start是开始选的元素,避免重复计算
            if (!k || !state) {//选了k个课,或者没课可选
                f[i | now] = min(f[i | now], f[i] + 1);
                return;
            }
            //当前可以选那些课
            for (int j = start; j < n; j ++ ) {
                if (state >> j & 1) {//如果state中包含这些课
                    dfs(n, k - 1, i, state - (1 << j), now + (1 << j), j + 1);
                    //state去掉当前选的课, now加上当前选的课
                }
            }
        }

    HUD 5148

    http://acm.hdu.edu.cn/showproblem.php?pid=5418

    递推:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 17;
    const int INF = 0x3f3f3f3f;
    int n, m, g[maxn][maxn], dp[1<<maxn][maxn];
     
    void floyd()
    {
        for(int k = 0; k < n; k++)
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    g[i][j] = min(g[i][j], g[i][k]+g[k][j]);
    }
     
    int main(void)
    {
        int t;
        cin >> t;
        while(t--)
        {
            scanf("%d%d", &n, &m);
            //对图进行初始化
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    g[i][j] = i==j ? 0 : INF;
            //插入边
            while(m--)
            {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                u--, v--;
                g[u][v] = min(g[u][v], w);
                g[v][u] = min(g[v][u], w);
            }
            //floyd算法
            floyd();
            memset(dp, INF, sizeof(dp));
            dp[0][0] = 0;
            for(int s = 0; s < 1<<n; s++)//遍历所有状态
                for(int v = 0; v < n; v++)//遍历所有节点
                    if(dp[s][v] != INF) 
                        for(int u = 0; u < n; u++)
                            dp[s|(1<<u)][u] = min(dp[s|(1<<u)][u], dp[s][v]+g[v][u]);
            printf("%d
    ", dp[(1<<n)-1][0]);
        }
        return 0;
    }

    递归:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn = 17;
    const int INF = 0x3f3f3f3f;
    int dp[1<<maxn][maxn], g[maxn][maxn], n, m;
     
    void floyd()
    {
        for(int k = 0; k < n; k++)
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    g[i][j] = min(g[i][j], g[i][k]+g[k][j]);
    }
     
    int dfs(int S, int v)
    {
        if(dp[S][v] >= 0) return dp[S][v]; // 状态已经遍历过
        if(S == (1<<n)-1 && v == 0) return dp[S][v] = 0;//回到终点
        int res = INF;
        for(int u = 0; u < n; u++)
        {
            if(!(S>>u & 1))//当前还没遍历过u节点,则遍历u节点
                res = min(res, dfs(S | 1<<u, u)+g[v][u]);
        }
        return dp[S][v] = res;
    }
     
    int main(void)
    {
        int t;
        cin >> t;
        while(t--)
        {
            scanf("%d%d", &n, &m);
            //将图初始化
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    g[i][j] = i==j ? 0 : INF;
            //加入边
            while(m--)
            {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                u--, v--;
                g[u][v] = min(g[u][v], w);
                g[v][u] = min(g[v][u], w);
            }
            //因为有些节点不是直接相连,进行floyd算法
            floyd();
            //dp 数组初始化
            memset(dp, -1, sizeof(dp));
            //dfs遍历
            printf("%d
    ", dfs(0, 0));
        }
        return 0;
    }
  • 相关阅读:
    汉语-谚语:条条大路通罗马
    汉语-词语:缱绻
    几何-对称图形:中心对称图形
    java解析获取Excel中的数据--同时兼容2003及2007
    如何使gcc输出搜索到的头文件路径?
    如何使tmux可以像vi一样操作(如快速跳转到某一行)?
    如何使tmux能够使用鼠标上下滚动?
    ID3v2: 为aac格式的音频文件添加ID3v2 Header
    FFmpeg: 利用FFmpeg提取音频文件中的metadata
    C语言:变长结构体
  • 原文地址:https://www.cnblogs.com/Aliencxl/p/13205202.html
Copyright © 2011-2022 走看看