状态压缩DP(棋盘类入门题(求方案数)+bitset解法)

状态压缩DP(棋盘类入门题(求方案数)+bitset解法)

反思

  • 将多个状态合并成(看成)一个状态来进行处理,并通过合并后的状态来优化问题的解决手段。
  • bitset是搭配状态压缩问题的一个很好用的工具。
  • 可以先对方案进行预处理,方便提取
  • 单行全为0的方案与其他所有方案都不冲突,可以增设一行,来吸收上一行的所有方案
  • 可行的方案数与行数没有直接挂钩。
  • 可以直接暴力,bitset写起来会比较麻烦一点

AcWing 1064. 小国王

#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;
}

AcWing 327. 玉米田

#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.
原文地址:https://www.cnblogs.com/BeautifulWater/p/15056110.html