问题 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;
}