首页 > 其他分享 >洛谷P2622 关灯问题II引发的关于DP实现形式及后效性的思考

洛谷P2622 关灯问题II引发的关于DP实现形式及后效性的思考

时间:2022-08-15 19:02:44浏览次数:64  
标签:后效 BFS 洛谷 010 II 100 include 递推

  动态规划要求已经求解的子问题不受后续阶段的影响,即无后效性。而在这种递推的实现方式中,后面枚举的状态可能更新前面已经枚举过的状态。也就是说,这种递推的实现方式是具有后效性的。
以这组数据为例

3
3
1 -1 1 
0 1 -1 
0 0 1

  正解应为 \(3\) 次(\(111 \to 010 \to 100 \to 000\)) 。

  而在递推时,\(100\) 在 \(010\) 之前被已被枚举,在 \(010\) 更新了 \(100\) 之后无法再通过 \(100\) 来得到目标状态 \(000\),便会得出 \(-1\)(无解)的错误答案。

//递推
#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::min;

int m, n, a[110][10], f[1 << 10];

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        for (int j = 0; j < n; ++j) {
            scanf("%d", &a[i][j]);
        }
    }
    memset(f, 0x3f, sizeof(f));
    f[(1 << n) - 1] = 0;
    for (int i = (1 << n) - 1; i >= 0; --i) {
        for (int k = 1; k <= m; ++k) {
            int t = i;
            for (int j = 0; j < n; ++j) {
                if (a[k][j] == 1 && (i & (1 << j))) t ^= 1 << j;
                if (a[k][j] == -1 && !(i & (1 << j))) t ^= 1 << j;
            }
            f[t] = min(f[t], f[i] + 1);
        }
    }
    printf("%d", f[0] == 0x3f3f3f3f ? -1 : f[0]);
    return 0;
}

  对于该题,适合使用记忆化BFS的实现方式。用BFS来进行记忆化搜索的这种实现方式可能比较少见,其实只是对于状态的遍历顺序不同。由于BFS的特性,每个状态在第一次被扩展到时便得到最优解。

//记忆化BFS
#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::min;

int m, n, head, tail, q[10000], a[110][10], f[1 << 10];
bool vis[1 << 10];

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        for (int j = 0; j < n; ++j) {
            scanf("%d", &a[i][j]);
        }
    }
    memset(f, 0x3f, sizeof(f));
    f[(1 << n) - 1] = 0;
    q[tail++] = (1 << n) - 1;
    vis[(1 << n) - 1] = true;
    while (head < tail) {
        int cur = q[head++];
        for (int i = 1; i <= m; ++i) {
            int t = cur;
            for (int j = 0; j < n; ++j) {
                if (a[i][j] == 1 && (cur & (1 << j))) t ^= 1 << j;
                if (a[i][j] == -1 && !(cur & (1 << j))) t ^= 1 << j;
            }
            if (vis[t]) continue;
            vis[t] = true;
            f[t] = f[cur] + 1;
            q[tail++] = t;
            if (t == 0) {
                printf("%d", f[t]);
                return 0;
            }
        }
    }
    printf("-1");
    return 0;
}

  当然,使用DFS+剪枝也可较为高效的解决该题。不过终究还是会重复遍历一些状态,比DP略慢。

标签:后效,BFS,洛谷,010,II,100,include,递推
From: https://www.cnblogs.com/znk161223/p/16589336.html

相关文章

  • 力扣-刷题-324. 摆动排序 II
    题目链接来源:力扣(LeetCode)链接:https://leetcode.cn/problems/wiggle-sort-ii著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。题目描述给你一个......
  • 安装IIS服务(转)
    操作场景本文档以WindowsServer2012R2操作系统和WindowsServer2008操作系统为例,介绍在Windows云服务器上进行IIS角色添加与安装。操作步骤WindowsServer......
  • Max Chunks To Make Sorted II
    MaxChunksToMakeSortedIIYouaregivenanintegerarray  arr.Wesplit arr intosomenumberofchunks(i.e.,partitions),andindividuallysorteachc......
  • 洛谷 P1654 OSU!
    思路考虑\(DP\)转移,设\(F[i]\)表示长度为\(i\)序列的期望分数。得到如下转移:\(F[i]=(F[i-1]-A[i-1]+A[i])p_i+F[i-1](1-p_i)\)其中\(A[i]\)的意义是:以\(i\)......
  • 洛谷-P2486 染色
    染色树链剖分考虑如果在数列上的话,就是用线段树处理这个问题线段树记录答案,并且处理区间和并的问题:如果区间合并的地方颜色相同,则加和后的答案要减一因此维护所有线段......
  • 洛谷P6812「MCOI-02」Ancestor 先辈
    洛谷P6812对于题目的区间加法明显可以用线段树或树状数组进行并且由题可得,先辈序列即为不下降序列,需满足ai<aj&&i<j判断一个序列是否为先辈我们比较的是一个元素和前一......
  • 洛谷 P6789 - 寒妖王(子集卷积+矩阵树定理)
    洛谷题面传送门像极了我验的那道牛客多校(第六场CForest)……考虑对于每条边,计算其在最大生成基环森林中的概率,乘以边权求和就是答案。现在问题在于如何计算每条边在最大......
  • SP1557 GSS2 - Can you answer these queries II(离线 线段树)
    SP1557GSS2-CanyouanswerthesequeriesII\(\bigstar\texttt{Hint}\):遇到去重的问题,我们通常考虑离线询问后处理。可以枚举右端点,将询问存储在右端点,考虑用数据结......
  • 8.14 洛谷月赛
    感觉没有tg难\(\rmLink\)目录\(T1\)\(T2\)\(T3\)(主打\(div2\))\(T1\)这个\(T1\)是个神仙题,我甚至为它写了一个\(45pts\)的暴力分然后过去切了\(T2\)再回来看才......
  • MinimalAPI---部署项目到IIS
    1.安装IIS,详情见:https://product.pconline.com.cn/itbk/vedio/1903/12395139.html2.安装ASP.NETCore运行时环境和程序包下载HostingBundle文件 安装包下载地址:https......