【SSLOJ1471】Y
题目
思路
设 \(f[i][j][s]\) 表示 \(i\) 到 \(j\) 之间是否存在状态为 \(s\) 的路径。时间复杂度 \(O(2^n\times n^2)\)。
显然这并不是一个可以接受的复杂度。发现可以 \(\operatorname{meet in the middle}\),又喜闻乐见的发现这是一个 \(\operatorname{bool}\) 数组,所以直接用 \(\operatorname{STL::bitset}\) 代替其即可。
然后计算答案的时候,枚举前后两段的状态,然后乘法原理即可。
时间复杂度 \(O(\frac{2^{\frac{d}{2}}\times n^2}{32}+2^d)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100,M=(1<<11);
int n,m,d,d1,d2,ans;
bitset<N> f[M],g[M],dis[2][N];
int main()
{
scanf("%d%d%d",&n,&m,&d);
d2=d/2; d1=d-d2;
for (int i=1,x,y,z;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
dis[z][x][y]=dis[z][y][x]=1;
}
for (int i=n;i>=1;i--)
{
for (int j=0;j<M;j++)
f[j].reset();
f[1][i]=1;
for (int s=1;s<(1<<d1);s++)
for (int j=1;j<=n;j++)
if (f[s][j]) f[s<<1]|=dis[0][j],f[(s<<1)|1]|=dis[1][j];
for (int s=0;s<(1<<d2);s++)
g[s][i]=f[s|(1<<d2)].any();
}
for (int i=0;i<(1<<d1);i++)
for (int j=0;j<(1<<d2);j++)
ans+=(f[(1<<d1)|i]&g[j]).any();
printf("%d",ans);
return 0;
}