状态压缩DP(棋盘类入门题(求方案数)+bitset解法)
反思
- 将多个状态合并成(看成)一个状态来进行处理,并通过合并后的状态来优化问题的解决手段。
- bitset是搭配状态压缩问题的一个很好用的工具。
- 可以先对方案进行预处理,方便提取
- 单行全为0的方案与其他所有方案都不冲突,可以增设一行,来吸收上一行的所有方案
- 可行的方案数与行数没有直接挂钩。
- 可以直接暴力,bitset写起来会比较麻烦一点
#include<bits/stdc++.h>
#define fir(i,a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
const int N = 11;
vector<bitset<N> > plans;
vector<bitset<N> > suit[1<<N];
bool check(bitset<N> x)
{
if( ((x>>1)&x).any() || ((x<<1)&x).any() )
return false;
return true;
}
int cnt_king(bitset<N> x)//返回x中1的个数
{
return x.count();
}
int main()
{
int n,k;
cin>>n>>k;
/****收集不连续站有两个国王的方案****/
fir(i,0,1<<n)
if(check(i))
plans.push_back(bitset<N>(i));
fir(i,0,plans.size())
fir(j,0,plans.size())
if( check( plans[i] | plans[j] ) && ( plans[i] & plans[j] ).none() )//把二进制合并成一行,检查一下,同时还外加一个上下检查
suit[plans[i].to_ulong() ].push_back(plans[j]);
ll f[n+2][k+1][1<<n];//f[i][j][k]表示的是前i行以k的二进制状态表示来结尾并拥有已经拥有k位国王的方案数
memset(f,0,sizeof(f));
f[0][0][0] = 1;//各种状态的起点;
for(int i=1;i<=n+1;i++)//行
for(int king=0;king<=k;king++)//国王量
for(int st=0;st<plans.size();st++)//可行方案的遍历
for(int up=0;up<suit[ plans[st].to_ulong() ].size();up++ )//直接找到可靠的小伙伴
if(king-cnt_king(suit[ plans[st].to_ulong() ][up]) >=0 )
f[i][king][plans[st].to_ulong() ] += f[i-1][ king-cnt_king(suit[ plans[st].to_ulong() ][up]) ][ suit[ plans[st].to_ulong() ][up].to_ulong() ];
cout<<f[n+1][k][0]<<endl;//状态0和所有状态都不起冲突,且0的国王数本身就是0,相当于把上一行所有的国王都拿走
return 0;
}
#include<bits/stdc++.h>
#define fir(i,a,b) for(int i=a;i<b;i++)
using namespace std;
const int N = 13, Mod = 1e8;//N取13
int n,m;
int dp[N][1<<N];//12*12*4096<4e8;
bitset<N> row[N];
vector<bitset<N> > plans;
vector<bitset<N> > suit[(1<<N)/2];//这里写错了,N应该改为1<<N,1到1<<N
bool check(bitset<N> x)
{
return ( x<<1 & x).none() && ( x>>1 & x).none();
}
int count_corn(bitset<N> x)
{
return x.count();
}
void init()
{
memset(dp,0,sizeof(dp));
}
int main()
{
cin>>n>>m;
init();
fir(i,1,n+1)
fir(j,0,m)
{
int x;
cin>>x;
row[i]<<=1;
if(x)row[i].set(0);//bitset不能直接加整数
}
fir(i,0,1<<m)//m写成n错了
if(check(i))
plans.push_back(bitset<N>(i));
fir(i,0,plans.size())
fir(j,0,plans.size())
if( (plans[i]&plans[j]).none() )
suit[i].push_back(plans[j]);
dp[0][0]=1;
fir(i,1,n+2)
fir(cur,0,plans.size())
if( (plans[cur] & row[i] ) == plans[cur] )//方案和土地实际情况不冲突, 方案包括在土地的实际情况中
fir(up,0,suit[cur].size())
dp[i][plans[cur].to_ulong()]=( dp[i][plans[cur].to_ulong()]+dp[i-1][ suit[cur][up].to_ulong()] ) % Mod;
cout<<dp[n+1][0];//汇合于一处
return 0;
}
其他
English
- artillery:炮兵
- The artillery bombarded the enemy all day.