#折半搜索,状压dp#nssl 1471 Y

题目
数据范围


分析

\(dp[i][j][s]\)表示从\(i\)\(j\)的一条路径状态为\(s\)是否存在
但是这样肯定会T掉,考虑拼凑路径,分成两部分,
\(dp[0/1][s]\)分别表示以某个起点/终点开始的一条路径状态为\(s\)是否存在,
现在表示一个点集,用出边的点集转移,可以用bitset维护,
然后如果\(dp[0][s]&dp[1][s']\)非空说明有中间点可以拼凑这两条路径
具体细节详见代码


代码

#include <cstdio>
#include <cctype>
#include <bitset>
#define rr register
using namespace std;
const int N=2048; int n,m,ans,t;
bitset<91>a[2][91],f[N],dp[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
signed main(){
	n=iut(); t=iut(); m=iut();
	while (t--){
		rr int x=iut(),y=iut(),z=iut();
		a[z][x][y]=a[z][y][x]=1;
	}
	rr int mid1=(m+1)>>1,mid2=m-mid1;
	for (rr int st=n;st;--st){
		for (rr int j=0;j<N;++j) f[j].reset();
		f[1][st]=1;
		for (rr int j=1;j<(1<<mid1);++j)
		for (rr int i=1;i<=n;++i) if (f[j][i])
		    f[j<<1]|=a[0][i],f[j<<1|1]|=a[1][i];
		for (rr int j=0;j<(1<<mid1);++j)
		    dp[j][st]=f[j|(1<<mid1)].any();
	}
	for (rr int i=0;i<(1<<mid1);++i)
	for (rr int j=0;j<(1<<mid2);++j)
	    ans+=(dp[i]&f[j|(1<<mid2)]).any();
	return !printf("%d",ans);
}
posted @ 2020-08-13 21:35  lemondinosaur  阅读(110)  评论(0编辑  收藏  举报