1. 程式人生 > >【題解】[SCOI2005] 互不侵犯 (狀壓DP)

【題解】[SCOI2005] 互不侵犯 (狀壓DP)

printf name clu .net ++ 版權 題解 long while

[SCOI2005] 互不侵犯

終於懂一點狀壓DP了…

用一個數的二進制形式表示一整行的狀態,
比如 18(1010)表示第一列和第三列有國王。

然後用&判斷是否可行:

if((x&y)||((x<<1)&y)||(x&(y<<1))) continue;
1
code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define FOR(i,n,m) for(register int i=n;i<=m;++i)

using namespace std;

int n,m,tot;
ll ans;
int can[1<<10],num[1<<10];
ll dp[10][1<<10][110];//dp[i][j][k]表示第i行,狀態為j,前面擺了k個國王時 的方案數

int sum(int x)//這一種狀態有多少個國王(一行)
{
while(x) num[tot]+=(x&1),x>>=1;
return num[tot];
}

int main()
{
scanf("%d%d",&n,&m);
int Max=(1<<n)-1;
FOR(i,0,Max) if(!(i&(i<<1))) can[++tot]=i,dp[1][tot][sum(i)]=1;

FOR(i,2,n)
{
FOR(j,1,tot) FOR(k,1,tot)
{
int x=can[j],y=can[k];
if((x&y)||((x<<1)&y)||(x&(y<<1))) continue;//判斷是否可行
FOR(l,0,m) dp[i][j][num[j]+l]+=dp[i-1][k][l];
}
}
FOR(i,1,tot) ans+=dp[n][i][m];
printf("%lld",ans);
return 0;
}
---------------------
作者:#shadow#
來源:CSDN
原文:https://blog.csdn.net/weixin_44663556/article/details/88378924
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

【題解】[SCOI2005] 互不侵犯 (狀壓DP)