lightoj 1287 Where to Run

57 篇文章 1 订阅
7 篇文章 0 订阅

感觉这个题的题面描述好坑啊,题目链接:lightoj1287

对于题目的理解是:由于需要时间尽可能长,那么需要尽可能的遍历全图

所以,最终的状态一定是从起点一笔画到了终点,中间无法走重复路径


这样的话,成了一个很经典的问题,n的数值很小,很明显是压缩dp解决这个概率问题

如何求该点的期望:

dp【u】=(5+dp【u】)/(cnt+1)+(mp【u】【i1】+mp【u】【i2】+……mp【u】【icnt】)/(cnt+1),其中,cnt是u合法连接的所有点数,mp【u】【ik】表示边数

如果cnt=0,说明该点是去不了的(看样例3),那么dp【u】=0

化简之后得到公式


设计状态:dp【u】【st】:为当前点在i点,状态为st的期望值(st为二进制压缩的,如st=0110,那么这个状态是去过1,2两个点的)

状态转移:

如果u和i相连那么mp【u】【i】>0

如果st状态中没有i这个点,即st&(1<<i)==0

如果st状态去了i点之后,可以到达终点遍历全图,即dp【i】【st|(1<<i)】>0

那么

dp【u】【st】+=dp【i】【st|(1<<i)】+mp【u】【i】


剩下的细节处理就是记忆化搜索需要做的事情了,代码如下:

int t,n,m;
double mp[maxn][maxn];
double dp[maxn][1<<maxn];
bool vis[maxn][1<<maxn];

int dfs(int st,int u){
	if (st==(1<<n)-1){
		dp[u][st]=0;
		return 1;
	}
	if (vis[u][st]) return dp[u][st]>eps;
	int cnt=0;
	dp[u][st]=5;
	vis[u][st]=true;
	for(int i=0;i<n;i++)
		if (mp[u][i]&&dfs(st|(1<<i),i)&&(!(st&(1<<i)))){
			int st0=st|(1<<i);
			cnt++;
			dp[u][st]+=mp[u][i]+dp[i][st0];
		}
	if (cnt){
		dp[u][st]/=cnt;
		return 1;
	}
	dp[u][st]=0;
	return 0;
}

int main(){
	//input;
	scanf("%d",&t);
	for(int Case=1;Case<=t;Case++){
		memset(dp,0,sizeof(dp));
		memset(mp,0,sizeof(mp));
		memset(vis,false,sizeof(vis));
		scanf("%d%d",&n,&m);
		int u,v,w;
		while(m--){
			scanf("%d%d%d",&u,&v,&w);
			mp[u][v]=mp[v][u]=1.0*w;
		}
		dfs(1,0);
		printf("Case %d: %.10lf\n",Case,dp[0][1]);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值