【DFS&反向建图&记忆化搜索】UPC Contest2592 - 2020年秋季组队训练赛第十四场 问题 D: Mysterious Treasure

该博客探讨了一种计算机科学问题,涉及有向无环图(DAG)上的路径优化。给定一张DAG,任务是通过最多删除一条边以最大化从起点到终点的概率。博主提供了详细的解题思路,包括使用记忆化搜索和递归方法来求解此问题。代码示例展示了如何实现这一算法,以找到最佳删除策略并计算最大概率。
摘要由CSDN通过智能技术生成

问题 D: Mysterious Treasure

时间限制: 1 Sec 内存限制: 128 MB

题目描述

WNJXYK and DIDIDI is playing a game. DIDIDI draws a directed graph G on the paper which contains n points, m directed edges and no cycle. WNJXYK starts from point 1. For every round, WNJXYK will randomly select one of the directed edges which start from current point with equal possibility, and go to next point by this edge. And the game will continue until such edge doesn’t exist. DIDIDI will place the treasure on point n, if WNJXYK go through this point, he can get the treasure. WNJXYK have one chance to delete one edge(he can also don’t choose to delete), that he can increase the probability of getting a treasure. Your assignment is to calculate the probability of WNJXYK getting the treasure in the optimal condition.

输入

The first line of input contains a positive integer T telling you there are T test cases followed.
For each test case, the first line contains two integers n , m, indicating the number of points ,the number of edges.
Then the following are m lines, each of which contains two integers x and y, indicating there is a edge from x to y.
It is guaranteed that there does not exist multiple edge.

输出

For each test case, print a line “Case #x: y”, where x is the case number (starting from 1) and y is the probability of he getting the treasure. (round to six decimal places).

样例输入 Copy

2
4 4
1 2
1 3
1 4
2 3
4 5
1 2
1 3
1 4
2 3
2 4

样例输出 Copy

Case #1: 0.500000
Case #2: 0.750000

提示

Tips:1≤T≤100,3≤n≤50,1≤m≤n(n-1)/2
Case 1: delete 1 - 2, 50% 1->3, 50% 1->4.
Case 2: delete 1 - 3, 25% 1->2->4, 25% 1->2->3, 50% 1->4.

向大佬低头 大佬博客 Orz

题目大意:给你一张有向无环图,你最多可以删除一条边(可以选择不删),问你从第一个点走到最后一个点的概率最大是多少。图来辅助解释。
在这里插入图片描述

解题思路:类似于累乘,使用记忆化搜索来代替直接相乘的情况,反向建图从最后一个点递归查找可到达点1的情况,递归边界,当条件为1时,概率即为1。对于原图的每个儿子节点,平均等分概率。(通俗一点的解释就是,有k个儿子的话,到达其中一个儿子节点的概率就是1/k;

附上代码:

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 110,M = 100010;
int h[N],e[M],ne[M],out[N],idx,n,m;
int delete_x,delete_y;
bool vis[110][110];
double flag[110];
void add(int a,int b)
{
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
double ans;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
double dfs(int x)
{
	double res=0.0;
	if(x==1)
	{
		res = 1.0;		
	}
	else{
		if(fabs(flag[x])>1e-7) return flag[x];
		for(int i=h[x];i!=-1;i=ne[i])
		{
			int j = e[i];
			if(x==delete_y&&j==delete_x) continue;
			res+=dfs(j)/out[j];
		}
	}	
	flag[x]=res;
	return res;
} 
int main()
{
	int t;
	t=read();
	int k=0;
	while(t--)
	{
		n=read(),m=read();
		memset(h,-1,sizeof h);
		memset(vis,false,sizeof vis);
		memset(out,0,sizeof out);
		ans=0.0;
		while(m--)
		{
			int x,y;
			x=read(),y=read();
			out[x]++;
			add(y,x);
			vis[x][y]=true;//x可以到达y 
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(vis[i][j])
				{
					delete_x=i,delete_y=j;
					memset(flag,0.0,sizeof flag);
					out[i]--;
					ans=max(ans,dfs(n));
					out[i]++;
				}
			}
		}
		memset(flag,0.0,sizeof flag);
		delete_x = -1,delete_y = -1;
		ans=max(ans,dfs(n));
		printf("Case #%d: %.6lf\n",++k,ans);
	}
	return 0;    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值