[CSP-S模拟测试]:y(DP+bitset)

题目背景

$frac{1}{4}$遇到了一道水题,叕完全不会做,于是去请教小$D$。小$D$懒得理$frac{1}{4}$,直接就离开了。于是,$frac{1}{4}$只好来问你,这道题是这样的:


题目描述

给定一个无向图,$n$个点(从$1$开始编号)、$m$条边(长度为$1$),每条边有一个权值$c(cin{0,1})$。
一条路径,可以表示为一个长度为经过边数的$01$串,串的第$i$位为经过的第$i$条边的权值。
两条路径相同,当且仅当表示其的$01$串相同。
求从$1$号点出发、长度为$d$的路径种数。


输入格式

从文件$y.in$中读入数据。
第一行,三个整数,$n,m,d$。
接下来$m$行,每行三个整数$u,v,c$,代表一条边连接$u$和$v$,权值为$c$。


输出格式

输出到文件$y.out$中。
输出一行,一个整数,代表答案。


样例

样例输入:

3 2 3
1 2 0
1 3 1

样例输出:

4


数据范围与提示

样例解释:

$1 ightarrow 2 ightarrow 1 ightarrow 2Rightarrow 000$
$1 ightarrow 2 ightarrow 1 ightarrow 3Rightarrow 001$
$1 ightarrow 3 ightarrow 1 ightarrow 2Rightarrow 110$
$1 ightarrow 3 ightarrow 1 ightarrow 3Rightarrow 111$

数据范围:

保证$nin [1,90],min [0,n imes (n−1)],din [1,20],u,vin [1,n],cin{0,1}$。


题解

考虑$DP$,设$dp[i][j][stack]$表示从$i$到$j$是否有一条状态为$stack$的连边。

那么显然时间复杂度是:$Theta(s^d imes n imes (n+m))$的。

考虑第一个优化,使用$bitset$,我们能够优化掉$j$那一维。

但是时间复杂度还是不够,于是我们考虑$meet in the middle$算法,只算前一半即可。

时间复杂度:$Theta(2^{frac{d}{2}} imes n imes (n+m)+2^d imes n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m,d;
bitset<90> bit[4][1100000];
long long ans;
int main()
{
	scanf("%d%d%d",&n,&m,&d);
	for(int i=1;i<=m;i++)
	{
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		if(c)bit[1][u][v]=bit[1][v][u]=1;
		else bit[0][u][v]=bit[0][v][u]=1;
	}
	int dis=(d+1)>>1;
	for(int i=n;i;i--)
	{
		for(int j=0;j<(1<<d);j++)bit[2][j].reset();
		bit[2][1][i]=1;
		for(int j=1;j<(1<<dis);j++)
			for(int k=1;k<=n;k++)
			{
				if(!bit[2][j][k])continue;
				bit[2][j<<1]|=bit[0][k];
				bit[2][j<<1|1]|=bit[1][k];
			}
		for(int j=0;j<(1<<dis);j++)
			bit[3][j][i]=bit[2][(1<<dis)|j].count()?1:0;
	}
	for(int i=0;i<(1<<dis);i++)
		for(int j=0;j<(1<<(d-dis));j++)
			if(((bit[3][i]&bit[2][(1<<(d-dis))|j]).count()))ans++;
	printf("%lld",ans);
	return 0;
}

rp++

原文地址:https://www.cnblogs.com/wzc521/p/11606517.html