NOIP提高模拟-20181017-T2-管道(状压DP)

写在前面

本来写了一个DFS强行暴力一发,然而DFS是错的,我写的DFS和标算的方法大相径庭,愉快爆零。

Solution

202020~40pts40pts40pts做法
直接暴搜即可。

606060~100pts100pts100pts做法
搜索+记忆化。

100pts100pts100pts做法详细解析
dpi,stadp_{i,sta}dpi,sta表示当前在iii点,已访问过的点集为stastasta时,将剩余所有能访问得到的点访问完后的总方案数。然而,似乎无法直接维护dpdpdp数组,因为在搜索的时候,剩下的所有能访问到的点的状态还未被计算,而在一张图上,又不能用循环进行状态转移。所以说我们需要借助一个辅助数组fff
fi,staf_{i,sta}fi,sta表示当前在iii点,已访问过的点集为stastasta时,访问剩余所有能访问得到的点后的状态,有了这个数组,我们就可以在计算dpdpdp数组时利用fff数组已经计算出来的状态,来更新dpdpdp数组。
又因为是无向图,所以dfsdfsdfs一个点以后会访问完所有与它联通的点才会回到这个点,那么我们可以得到转移方程:
dpi,sta=∑jdpj,sta∣2j∗dpi,sta∣fj,sta dp_{i,sta}=\sum_j dp_{j,sta|2^{j}}*dp_{i,sta}|f_{j,sta} dpi,sta=jdpj,sta2jdpi,stafj,sta
对于fff,可以直接dfsdfsdfs求,时间复杂度O(n22n)O(n^22^n)O(n22n)
Talk is Cheap, Show You the Code:

#include
using namespace std;
const int N=20;
const int mod=998244353;
const int M=450;
int read(){
	int sum=0,neg=1;
	char c=getchar();
	while(c>'9'||c<'0'&&c!='-') c=getchar();
	if(c=='-') neg=-1,c=getchar();
	while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar();
	return sum*neg;
}
int n,m;
struct Edge{
	int u,v;
}e[M<<1];
int first[M],nxt[M],cnt=0;
void AddEdge(int u,int v){
	e[++cnt].u=u;e[cnt].v=v;
	nxt[cnt]=first[u]; first[u]=cnt;
}
int f[1<<N][N];
int dfs1(int sta,int u){
	if(f[sta][u]) return f[sta][u];
	f[sta][u]=sta;
	for(int i=first[u];i;i=nxt[i]){
		int v=e[i].v;
		if(!(sta&(1<<v))) f[sta][u]|=dfs1(sta|(1<<v),v);//没有访问过
			
	}
	return f[sta][u];
}
long long dp[1<<N][N];
int dfs(int sta,int u){
	if(f[sta][u]==sta) return 1;
	if(dp[sta][u]!=-1) return dp[sta][u];
	dp[sta][u]=0;
	for(int i=first[u];i;i=nxt[i]){
		int v=e[i].v;
		if(sta&(1<<v)) continue;
		int x=dfs(sta|(1<<v),v);
		int y=dfs(f[sta|(1<<v)][v],u);
		dp[sta][u]+=(long long)x*y%mod;
	}
	return dp[sta][u]%=mod;
}
int main(){
	n=read(); m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read()-1; v=read()-1;
		AddEdge(u,v);
		AddEdge(v,u);
	}
	for(int i=0;i<(1<<n);i++)
		for(int j=0;j<n;j++)
			if(i&(1<<j)) f[i][j]=dfs1(i,j);//i表示全图访问状态的一个子集
	memset(dp,-1,sizeof(dp));
	long long ans=0;
	for(int i=0;i<n;i++) ans+=dfs(1<<i,i);
	printf("%lld\n",ans%mod);
}

转载于:https://www.cnblogs.com/Neonen/p/9832493.html

你可能感兴趣的:(NOIP提高模拟-20181017-T2-管道(状压DP))