状态压缩-动态规划
---By蒟蒻鱼
用二进制表示城市的到达(规划的)状态
每一个二进制数都代表一个唯一的十进制数
预备知识
- 位运算
优先级
~
<< 和 >>
&
^
|
按位与 & 全一则一,否则为零
按位或 | 有一则一,否则为零
按位取反 ~ 是零则一,是一为零
按位异或 ^ 不同则一,相同为零
移位 >> <<
基本运算:
集合取并 A|B
集合取交 A&B
集合相减 A&~B
集合相减 ALLBITS~A
置位 A|1<<bit
清位 A^(1<<bit)
TSP问题
dp[i][j]代表已经走过城市的方案为i,当前所在j号城市的最短路径的长度
DP方程:
dp[i][j]=min(dp[i^(1<<j-1)][k]+dis[k][j])
i^(1<<j-1)清除j的前驱
合法布阵问题
判断上下两行相邻:st[i]&(i<<1)如果大于零,则有相邻
是否在贫瘠的土地上放了牛:map[i]&st[k]>=1则说明在贫瘠的土地上放了牛
则不合法.(map贫瘠为一)
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int mod=100000000;
int n,m;
int st[1<<12],map[1<<12];//分别表示每一行的状态和草地的状态
int dp[15][1<<12];
int main()
{
scanf("%d%d",&n,&m);
int x;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
if(x==0)map[i]=map[i]|(1<<j-1);
}
int k=0;
for(int i=0;i<(1<<m);i++)//计算每行合法的放置方式
{
if(!(i&(i<<1)))st[++k]=i;
}
for(int i=1;i<=k;i++)//特判第一行
{
if(!(st[i]&map[1]))dp[1][i]=1;
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
if(!(map[i]&st[j]))for(int r=1;r<=k;r++)
{
if(!(map[i-1]&st[r]))
{
if(!(st[j]&st[r]))dp[i][j]+=dp[i-1][r];
}
}
}
}
int ans=0;
for(int i=1;i<=k;i++)
{
ans=(ans+dp[n][i])%mod;
}
printf("%d",ans);
return 0;
}
end