【BZOJ】1087: [SCOI2005]互不侵犯King(状压dp)
http://www.lydsy.com:808/JudgeOnline/problem.php?id=1087
状压dp是第一次写啊,我也是才学TAT。状压dp一般都用一个值表示集合作为dp的一个状态,然后根据集合和dp的性质转移。通常用于啥啥啥。。。。。
我引用些吧
我们知道,用DP解决一个问题的时候很重要的一环就是状态的表示,一般来说,一个数组即可保存状态。但是有这样的一些题目,它们具有DP问题的特性,但是 状态中所包含的信息过多,如果要用数组来保存状态的话需要四维以上的数组。于是,我们就需要通过状态压缩来保存状态,而使用状态压缩来保存状态的DP就叫 做状态压缩DP。
回到此题:
设状态f[i][j][k]表示前i行放j个国王且在第i行放置国王的情况为k时的方案数
有
f[i][j][k]=sum{ f[i-1][j-cnt[x]][x] | x为所有不与k互斥的放置情况,cnt[x]为放置为x时国王的数量 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <cmath> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define read(a) a=getnum() #define print(a) printf("%d", a) inline int getnum() { int ret=0; char c; for (c= getchar (); c< '0' || c> '9' ; c= getchar ()); for (; c>= '0' && c<= '9' ; c= getchar ()) ret=ret*10+c- '0' ; return ret; } long long f[10][82][512], ans; bool c1[512], c2[512][512]; int cnt[512], n, m, bit; void init() { bit=(1<<n)-1; int s, t; for1(i, 0, bit) if ((i&(i>>1))==0) { t=i; s=0; while (t) { if (t&1) ++s; t>>=1; } cnt[i]=s; c1[i]= true ; } for1(i, 0, bit) if (c1[i]) for1(j, 0, bit) if (c1[j]) if ((i&(j>>1))==0 && (j&(i>>1))==0 && (i&j)==0) c2[i][j]= true ; } int main() { read(n); read(m); init(); int p; for1(i, 0, bit) if (c1[i]) f[1][cnt[i]][i]=1; for1(i, 2, n) for1(j, 0, bit) if (c1[j]) for1(k, 0, bit) if (c1[k]) if (c2[j][k]) { for (p=cnt[k]; p+cnt[j]<=m; ++p) f[i][p+cnt[j]][j]+=f[i-1][p][k]; } for1(i, 0, bit) ans+=f[n][m][i]; printf ( "%lld" , ans); return 0; } |
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
HINT
Source
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步