题意描述略,有点繁琐,点此GodFly的寻宝之旅
题解:由于只有18位,用状压DP。
首先读入边,r[i][j]表示i,j之间连边数量。
定义状态:f[i][s][w]表示停留在i点,路径集合为s,花费为w时方案总数,则答案即为sigma(f[n][s][q]),其中s为任意状态。
初始化:f[1][1][0]=1;
状态转移方程:设从i点,状态为s转移到t点,则有
f[t][s|(1<<t-1)][(0+t×num[s])%2]+=f[i][s][0]×r[i][t]
f[t][s|(1<<t-1)][(1+t×num[s])%2]+=f[i][s][1]×r[i][t]
即 下一状态方案数 +=当前方案数×转移的路径条数
很重要的一点:要先枚举状态s,在每个状态中枚举i和t。
为什么?因为如果在i或t中枚举s,则会出现「用一个还没有更新的状态去更新另一个状态」的情况。此时的答案是错误的。
最后ans=sigma(f[n][s][q]),q为询问状态。
题解结束
正文开始
位运算/状压DP常用技巧:
每位只有0,1两种状态,共有n位,枚举所有状态:
for(int s(0);s<=(1<<n)-1;s++)
第i位为1的二进制表示:
(1<<i-1)
判断状态s第i位是否为1(判断是否已经选过)
return (1<<i-1)&s
若为1,则在(i和s都为1)
若为0,不在。
将s的第i位设置为1
s=s|(1<<t-1)
| 表示按位或