bzoj1087 [SCOI2005]互不侵犯King(状压dp)
2017-08-16 10:11
459 查看
压缩每一行的状态,1表示放国王,0表示不放国王,则一行有2n种状态,预处理每行的可能合法状态,即相邻的位置不能同为1,顺便记录cnt,表示此状态放了多少个国王(即状态i有多少个位为1)。然后再预处理相邻两行的合法状态(相同位置不同为1,左上右下相邻位置不同为1,左下右上相邻位置不同为1)。dp[i][j][k]表示前i行一共放了j个king,第i行状态为k的方案总数,则
dp[i][j][k]=sum{dp[i-1][j-cnt[k][kk]|f2[kk][k]==1}
时间复杂度O(n∗2n∗2n)
dp[i][j][k]=sum{dp[i-1][j-cnt[k][kk]|f2[kk][k]==1}
时间复杂度O(n∗2n∗2n)
#include<cstdio> #define ll long long #define N 10 int n,m,cnt[512]; bool f1[512],f2[512][512]; ll dp [N*N][512];//dp[i][j][k]表示前i行一共放了j个king,第i行状态为k的方案总数 int main(){ scanf("%d%d",&n,&m); //预处理每行可能合法的状态 int tot=(1<<n)-1; for(int i=0;i<=tot;++i) if((i&(i>>1))==0){//相邻两格不能同为1 f1[i]=1; for(int x=i;x;x>>=1) cnt[i]+=x&1;//cnt[i]统计状态i放了多少个国王 } for(int i=0;i<=tot;++i) if(f1[i])//预处理相邻的两行合法的状态 for(int j=0;j<=tot;j++) if(f1[j]) if((i&j)==0&&(i&(j>>1))==0&&(i&(j<<1))==0) f2[i][j]=1; for(int i=0;i<=tot;++i) if(f1[i]) dp[1][cnt[i]][i]=1; for(int i=2;i<=n;++i) for(int j=0;j<=tot;++j)//第i-1行为j状态 for(int k=0;k<=tot;++k)//转移到第i行的k状态 if(f2[j][k]) for(int p=cnt[j];p+cnt[k]<=m;++p) dp[i][p+cnt[k]][k]+=dp[i-1][p][j]; ll ans=0; for(int i=0;i<=tot;i++) ans+=dp [m][i]; printf("%lld\n",ans); return 0; }
相关文章推荐
- BZOJ1087: [SCOI2005]互不侵犯King 题解【DP】【状压】
- 【bzoj 1087】[SCOI2005]互不侵犯King 状压dp
- [BZOJ1087][SCOI2005]互不侵犯King解题报告|状压DP
- bzoj 1087: [SCOI2005]互不侵犯King 状压dp
- 【BZOJ】1087: [SCOI2005]互不侵犯King(状压dp)
- 【BZOJ1087】【SCOI2005】互不侵犯King(状压dp)
- BZOJ 1087 SCOI2005 互不侵犯King 状压DP
- BZOJ 1087 [SCOI2005]互不侵犯King ——状压DP
- [bzoj1087]: [SCOI2005]互不侵犯King(状压dp)
- BZOJ 1087: [SCOI2005]互不侵犯King | 状压DP
- bzoj 1087: [SCOI2005]互不侵犯King 状压dp
- 【bzoj1087】[SCOI2005]互不侵犯King 状压DP
- Bzoj 1087: [SCOI2005]互不侵犯King(状压DP)
- 【BZOJ】1087 [SCOI2005]互不侵犯King 状压DP(轮廓线DP)
- [BZOJ1087][SCOI2005]互不侵犯King(状压dp)
- BZOJ 1087 [SCOI2005]互不侵犯King (状压DP)
- BZOJ 1087: [SCOI2005]互不侵犯King 预处理,状压DP
- BZOJ 1087 [SCOI 2005] 互不侵犯的king (状压DP)
- BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )
- BZOJ 状态压缩dp 1087: [SCOI2005]互不侵犯King