HDU1287 Where to Run(记忆化搜索dp)

vj传送门

首先需要预处理每个状态哪些点可以遍历完图

这个过程可以记忆化搜索

临界点是状态为 ( 1 < < n ) − 1 (1<<n)-1 (1<<n)1,包含所有点,此时无论在哪个点都遍历完全图了

由此可以开始 d f s dfs dfs,能到达这个状态的也能遍历全图…

这样预处理后, d p dp dp就变得方便很多了

再来一遍 d f s dfs dfs d p dp dp即可

#include <bits/stdc++.h>
using namespace std;
const int maxn=(1<<15)+10;
double dp[maxn][16],cnt[maxn][16];
int t,n,m,mx,mp[maxn][16];
struct edge{
	int to,nxt; double w;
}d[maxn]; int head[maxn],k=1;
void add(int u,int v,double w){
	d[++k]=(edge){v,head[u],w},head[u]=k;
}
int dfs(int u,int sta)
{
	if( mp[sta][u]!=-1 )	return mp[sta][u];
	if( sta==mx )	return mp[sta][u]=1;
	cnt[sta][u]=mp[sta][u]=0;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( (sta&(1<<v))||!dfs(v,sta|(1<<v)) )	continue;
		mp[sta][u]=1;	cnt[sta][u]++;
	}
	return mp[sta][u];
}
double DP(int u,int sta)
{
	if( dp[sta][u]!=-1 )	return dp[sta][u];
	if( sta==mx||cnt[sta][u]==0 )	return dp[sta][u]=0;
	double p=1.0/(cnt[sta][u]+1);
	dp[sta][u] = 5.0*p;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( (sta&(1<<v))||!mp[sta|(1<<v)][v] )	continue;
		dp[sta][u]+=( DP(v,sta|(1<<v))+d[i].w )*p;
	}
	dp[sta][u]/=(1-p);
	return dp[sta][u];
}
int main()
{
	cin >> t;
	int casenum=0;
	while( t-- )
	{
		cin >> n >> m;
		mx = (1<<n)-1;
		for(int i=0;i<=mx;i++)
		for(int j=0;j<n;j++)
			mp[i][j]=dp[i][j]=-1,cnt[i][j]=0;
		for(int i=1;i<=m;i++)
		{
			int l,r; double w; cin >> l >> r >> w;
			add(l,r,w); add(r,l,w);
		}
		dfs(0,1);
		printf("Case %d: %.7lf\n",++casenum,DP(0,1) );
		k=1;
		for(int i=0;i<=n;i++)	head[i]=0;
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值