浅谈轮廓线DP
本文将粗略讲解轮廓线 DP 的基础原理、状态设计与实现模板,结合经典网格计数例题帮助读者掌握该算法。若文章存在错误或优化建议,欢迎在评论区留言指正。
前置说明
阅读本文需要掌握状压 DP 基础知识点。若无相关基础,可自行查阅前置资料,后续会更新状压 DP 基础讲解文章。
配套例题
建议结合两道经典网格 DP 例题实操学习,可快速吃透轮廓线 DP 核心逻辑:
P1879 USACO06NOV Corn Fields G:网格种草计数基础模板题
P1896 SCOI2005 互不侵犯:八方向限制拓展练习题
一、算法优势
轮廓线 DP 是面向网格、棋盘模型的状压 DP 进阶算法,能够解决普通逐行状压 DP 无法覆盖的网格计数问题,算法效率远高于朴素 DFS。
该算法采用逐格转移的方式,计算精度更高;仅存储局部轮廓线状态,时空复杂度更优,是 12 * 12 及以内小规模网格计数问题的最优解法。
二、核心解题思路
当题目网格中存在上下、左右相邻格子的放置限制、禁止相邻选取等约束条件时,可优先使用 轮廓线 DP 。本文将结合经典例题 P1879 USACO06NOV Corn Fields G 完整讲解算法原理与实现。
2.1 状态设计
定义记忆化 DP 数组 dpijs,其中 i,j 为当前遍历的网格坐标(下标从 0 开始),s 为轮廓线状态压缩值。
状态释义:s 的第 0 ~ j-1 位,记录当前第 i 行已遍历列的格子状态;s 的第 j 位及后续位数,记录上一行(i-1 行)对应列的格子状态。数组存储对应位置、对应轮廓线状态下的合法方案总数。
为方便理解状态转移逻辑,结合网格状态示例进行说明:
| 0 列 | 1 列 | 2 列 | 3 列 | 4 列 | 5 列 | 6 列 | |
|---|---|---|---|---|---|---|---|
| 0 行 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
| 1 行 | 1 | 0 | 0 | 1 | 0 | 1 | 1 |
遍历至不同坐标时,轮廓线状态 s 的取值如下:
在 i=1,j=0 时,s=1010000。
在 i=1,j=1 时,s=1010000。
在 i=1,j=2 时,s=1010000。
在 i=1,j=3 时,s=1000000。
在 i=1,j=4 时,s=1001000。
在 i=1,j=5 时,s=1001000。
在 i=1,j=6 时,s=1001010。
在 i=1,j=7 时,s=1001011。
2.2 完整代码实现
为适配书写习惯,代码中将题目输入的行列数进行互换,最终代码可正常 AC 对应题目,全文下标从 0 开始。
cpp
// 全文使用 based-0
#include<iostream>
using namespace std;
#define mod 100000000
int dp[15][15][5000];
int k[15][15];
int n,m;
int set(int s,int i,int v) //设置状态
{
return v==0?s&(~(1<<i)):s|(1<<i);
}
int get(int s,int i) //获取状态
{
return (s>>i)&1;
}
int f(int i,int j,int s) //轮廓线DP
{
if(i==n)return 1; //全部dp完了,证明此方案有效,返回1
if(j==m)return f(i+1,0,s); //下一行
if(dp[i][j][s]!=-1)return dp[i][j][s]; //记忆化
int ans;
ans=f(i,j+1,set(s,j,0))%mod; //不种草一定可以,所以直接下一列
if(((j>0&&(!get(s,j-1))&&(!get(s,j)))||(j==0&&(!get(s,j))))&&k[i][j]) //当且仅当上一行和左边一列状态为0(没种菜),且这个地方可以种草
ans=(ans+f(i,j+1,set(s,j,1)))%mod;
return dp[i][j][s]=ans; //记忆化
}
int main()
{
cin>>n>>m; //n和m互换
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>k[i][j];
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int p=0;p<=(1<<12);p++)
dp[i][j][p]=-1; //标记为未访问
cout<<f(0,0,0);
return 0;
}
看到这里可能你还不太理解,所以附上一个友情链接 。
三、学习总结
熟练掌握本文的状态设计思路与模板代码,并独立通过两道配套例题,即可掌握轮廓线 DP 的基础用法,能够独立解决基础网格限制类计数问题。
若对文章内容有补充建议、发现笔误或存在算法疑问,可在评论区留言或私信交流探讨。