I. 引入
[USACO06NOV] Corn Fields G
轮廓线 dp 入门题。
逐格枚举,考虑到未决策点仅会受到决策点与未决策点交界处点影响,引入轮廓线(这题是格子)。注意到 n n n 范围很小,状压。
记 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示枚举到 ( i , j ) (i,j) (i,j) 轮廓线状态为 k k k 的方案数。
当前格 ( i , j ) (i,j) (i,j) 转移到下一格,考虑 ( i , j ) (i,j) (i,j) 填不填:
-
上面已填, ( i , j ) (i,j) (i,j) 必不填,下一格轮廓线第 j j j 列改为 0 0 0。
-
左边已填或者 a ( i , j ) = 0 a(i,j)=0 a(i,j)=0, ( i , j ) (i,j) (i,j) 必不填,下一格轮廓线不变。
-
其余情况填或不填均可,分别转移。
f[1][1][0] = 1;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
int nxti, nxtj;
(j == m) ? (nxti = i + 1, nxtj = 1) : (nxti = i, nxtj = j + 1);
for(int k=0; k<=ALL; k++)
{
bool up = (1 << j-1) & k;
bool left = (j == 1) ? 0 : (1 << j-2) & k;
if(i == 1 and up) continue;
if(up)
add(f[nxti][nxtj][k-(1<<j-1)], f[i][j][k]);
else if(left or !a[i][j])
add(f[nxti][nxtj][k], f[i][j][k]);
else
add(f[nxti][nxtj][k], f[i][j][k]),
add(f[nxti][nxtj][k+(1<<j-1)], f[i][j][k]);
}
}
}
注意到每次转移只与上一格有关,考虑滚动数组。代码
HDU Eat the Trees
插头 dp 入门题。
引入了插头的概念,插头有上下左右四种,通过插头可以保证连通性。
当前格 ( i , j ) (i,j) (i,j) 转移到下一格:
- ( i , j ) (i,j)