补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点:
5 6 7 8 9
1 2 3 4
如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了。注意多记录些信息对简化代码是很有帮助的,尤其对于我这种代码经常错的一塌糊涂的人来说。。
呆马:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <vector> #define inf 1000000007 #define oo 100000000 #define maxn 15 #define maxm 5200 using namespace std; int n,m,mb; int a[maxn][maxn]; int f[maxn][maxn][5000]; int bit[5000][maxn]; bool legal(int x, int y,int mask) { if (y==1) if (bit[mask][y]&bit[mask][y+1]) return 0; for (int i=1;i<y-1;i++) if (bit[mask][i]&bit[mask][i+1]) return 0; for (int i=y;i<m;i++) if (bit[mask][i]&bit[mask][i+1]) return 0; return 1; } int main() { scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]); mb=(1<<m)-1; for (int mask=0;mask<=mb;mask++) { int tmp=mask; for (int i=1;i<=m;i++) { bit[mask][i]=tmp%2; tmp/=2; } } memset(f,0,sizeof(f)); f[0][m][0]=1; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int mask=0;mask<=mb;mask++) if (legal(i,j,mask)) { int tmp=1<<(j-1); if (j==1) { f[i][j][mask&(~tmp)]+=f[i-1][m][mask]; f[i][j][mask&(~tmp)]%=oo; if (!bit[mask][j] && a[i][j]) { f[i][j][mask|tmp]+=f[i-1][m][mask]; f[i][j][mask|tmp]%=oo; } } else { f[i][j][mask&(~tmp)]+=f[i][j-1][mask]; f[i][j][mask&(~tmp)]%=oo; if (!bit[mask][j] && a[i][j]) { f[i][j][mask|tmp]+=f[i][j-1][mask]; f[i][j][mask|tmp]%=oo; } } } int ans=0; for (int mask=0;mask<=mb;mask++) if (legal(n+1,1,mask)) { ans+=f[n][m][mask]; ans%=oo; } printf("%d\n",ans); return 0; }
Corn Fields
时间: 2024-10-05 04:26:05