Problem Description
有一棵 n 个节点的石榴树,点的下标为 1…n,下标为 m 的节点上有一颗石榴。石榴树有 2n−2 条有向边,每条有向边都连接两个不同的节点,不存在完全相同的两条有向边,且如果从节点 a 到节点 b 的有向边存在,反过来从节点 b 到节点 a 的有向边也必定存在。从任意一个节点都能(经过这些有向边中的若干条)到达任意一个其它节点。
现在有两只小蚂蚁去找石榴。
两只小蚂蚁都从 1 号点出发,第一只蚂蚁先走。它每次会从它当前所在的节点出发的没有走过的有向边中等概率地选择一条走(注意从 a 到 b 和从 b 到 a 是两条不同的有向边),并且在这条有向边上留下信息素。如果蚂蚁找到了石榴,或者无路可走了,它就会停下来。
第一只蚂蚁停下来以后第二只蚂蚁走,它每次从它当前所在的节点出发的有第一只蚂蚁留下的信息素且自己没走过的有向边中等概率地选择一条走。如果第二只蚂蚁找到了石榴,或者它无路可走了,它就会停下来。
如果第二只蚂蚁沿着从 1 到 m 的最短路找到了石榴,就说它成功了。请问对于第一只蚂蚁,使得第二只蚂蚁成功率大于等于 1/2 的概率是多少?
Input
第一行一个正整数 test (1≤test≤100) 表示数据组数。
对于每组数据,第一行两个正整数 n,m (1≤n≤100000,1≤m≤n) 分别表示点数和石榴在哪里。
接下来 n−1 行描述 2n−2 条有向边,每行两个整数 x,y 代表从 x 到 y 和从 y 到 x 各有一条有向边。
数据保证读入是一棵合法的石榴树,数据保证树是这样随机生成的:
for (int i = 1; i <= n; i++)
a[i] = i;
random_shuffle(a + 1, a + n + 1);
for (int i = 2; i <= n; i++)
连接编号为 a[i] 和 a[j] 的点,其中 j 为 {1, ..., i-1} 中一个随机的整数。每次随机相互独立。
(实际上每次随机使用了C++自带的随机函数。)
Output
对于每组数据,一行一个数表示答案。由于答案 A/B 中的 AB 可能很大,请输出 A/Bmod(109+7)。假设 A/B 为最简分数,A/Bmod(109+7)=A×B−1mod(109+7),B−1 为满足 B−1×Bmod(109+7)=1 的整数。
Sample Input
3
1 1
4 2
1 2
1 3
1 4
5 4
1 2
1 3
3 4
3 5
Sample Output
1
666666672
416666670
Source
2020 年百度之星·程序设计大赛 - 初赛三
思路:
因为第二只蚂蚁只会根据第一只蚂蚁留下信息素的路径走,所以只需要考虑第一只蚂蚁是否走到石榴即可。
走到石榴分为两种情况,一种是直接走到,这个路径是唯一的;另一种是“拐弯”再走到。
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;
vector<int>G[maxn];
ll f1[maxn],f2[maxn];
ll qpow(ll x,ll n) {
ll res = 1;
while(n) {
if(n & 1) {
res = res * x % mod;
}
n >>= 1;
x = x * x % mod;
}
return res;
}
void dfs(int x,int fa,int m) {
if(x == m) {
f1[x] = 1;
return;
}
for(int i = 0;i < G[x].size();i++) {
int v = G[x][i];
if(v == fa) continue;
dfs(v,x,m);
int tmp = (x != 1);
if(f1[v]) {
f1[x] = f1[v] * qpow((ll)G[x].size(),mod - 2) % mod;//从x出发直接走到石榴的概率
f2[x] = f2[v] * qpow((ll)G[x].size(),mod - 2) % mod; //从x出发走到石榴且在子树中发生拐弯的概率
f2[x] = (f2[x] + f1[x] * qpow((ll)G[x].size() - 1,mod - 2) % mod * (ll)(G[x].size() - 1 - tmp) % mod) % mod; //从x出发走到石榴且在x也发送了拐弯的概率
}
}
}
int main() {
int T;scanf("%d",&T);
while(T--) {
int n,m;scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++) {
G[i].clear();
f1[i] = f2[i] = 0;
}
for(int i = 1;i < n;i++) {
int x,y;scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,-1,m);
printf("%lld\n",(f1[1] + f2[1]) % mod);
}
return 0;
}