下午花了两个小时把Yali中学 陈丹琦的《基于连通性状态压缩的动态规划问题》啃完,,,
插头DP还真是个麻烦的东西。。。
相较SGU223算一个水题了,
给定N*N的棋盘,摆放m个不相互攻击的棋子,棋子攻击范围为相邻8个位置。求方案数。
dp[i][j][k],第i行,状态为j,放了k个棋子的方案数,dp[i][j][k] = sum(dp[i-1][jj][k - cnt(j)])
详见代码:


#include<stdio.h> #include<string.h> #include<math.h> #define LL long long #define N 11 int n; int m; LL dp[11][1024][111]; int cnt[1024]; int get_cnt(int x) { int res = 0; while (x) { if (x % 2 == 1) res++; x /= 2; } return res; } bool check(int x) { if ((((x<<1)&x) == 0) && (((x>>1))&x) ==0) return 1; return 0; } bool calc(int x,int y) { if (((x&y) == 0) && (((x<<1)&y)==0) && (((x>>1)&y)==0)) return 1; return 0; } int main() { scanf("%d%d",&n,&m); memset(dp,0,sizeof(dp)); memset(cnt,-1,sizeof(cnt)); for (int i=0; i<=(1<<n)-1; i++) { if (check(i)) { cnt[i] = get_cnt(i); } } dp[0][0][0] = 1; for (int i=1; i<=n; i++) for (int j=0; j<=(1<<n)-1; j++) if (cnt[j]>=0) { for (int k=0; k<=(1<<n)-1; k++) if (cnt[k]>=0 && calc(k,j)) { for (int s=0; s<=m; s++) { if (s - cnt[j]>=cnt[k]) { dp[i][j][s] += dp[i-1][k][s - cnt[j]]; } } } } LL ans = 0; for (int j=0;j<=(1<<n)-1;j++) if (cnt[j]>=0){ ans += dp[n][j][m]; } printf("%I64d\n",ans); return 0; }