now886H(最短路)

题目链接

https://ac.nowcoder.com/acm/contest/886/H

题意

给定 $n$ 个点 $m$ 条权值为 $1$ 的无向图,给定点集 $A$ 和 $B$ ,有一个人会等概率在 $A$ 中的某一个点,有一个人会等概率在 $B$ 中的某个一点,有一个人等概率出现在 $n$ 个点中,他们三人选择一个最优点汇合,问三人走到汇合点的路径和的期望(先确定各自的位置后确定最优汇合点)

题解

这个题有点神奇。。首先要能够作一些转化,枚举 $A$ 和 $B$ 的位置,然后再快速确定第三个人的位置和汇合点的贡献。记 $d[i]=dis(a,i)+dis(b,i)$,然后跑一遍多源多汇的最短路即可。。

简单的想法可以通过建超级源点跑最短路,然而会 $TLE$ ,需要严格 $O(m)$

很容易想到需要利用边权为 $1$ 的性质 ,这个带来的好处是 $d[i]\le n$ ,利用这个我们可以利用桶排来代替优先队列,然后直接把复杂度降到 $O(n+m)$




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<complex>
#include<cstdlib>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define mid (x+y>>1)
#define sqr(x) ((x)*(x))
#define NM 100005
#define nm 200005
using namespace std;
const double pi=acos(-1);
const int inf=1e9+7;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}



struct edge{int t;edge*next;}e[nm],*h[NM],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
int n,m,_x,_y,_t,a[21],b[21],ca,p, _a[21][NM],_b[21][NM],d[NM];
ll ans,_ans;
bool v[NM];
queue<int>q;


void bfs(int u){
inc(i,1,n)d[i]=inf,v[i]=false;
d[u]=0;q.push(u);
while(!q.empty()){
int t=q.front();q.pop();
link(t)if(d[j->t]>d[t]+1){
d[j->t]=d[t]+1;
if(!v[j->t])q.push(j->t),v[j->t]++;
}
}
}
vector<int>vec[NM];
void bfs(){
inc(i,1,n)v[i]=false;
inc(i,0,n)for(auto&t:vec[i])if(!v[t]){
v[t]++;
link(t)if(d[j->t]>d[t]+1)vec[d[j->t]=d[t]+1].push_back(j->t);
}
}

int main(){
srand(time(0));
int _=read();while(_--){
n=read();m=read();o=e;mem(h);
inc(i,1,m){_x=read();_y=read();add(_x,_y);add(_y,_x);}
m=read();inc(i,1,m)a[i]=read();
p=read();inc(i,1,p)b[i]=read();
inc(i,1,m){
bfs(a[i]);
inc(j,1,n)_a[i][j]=d[j];
}
inc(i,1,p){
bfs(b[i]);
inc(j,1,n)_b[i][j]=d[j];
}
ans=0;
inc(i,1,m)inc(j,1,p){
inc(k,0,n)vec[k].clear();
inc(k,1,n){
d[k]=_a[i][k]+_b[j][k];
if(d[k]<=n)vec[d[k]].push_back(k);
}
bfs();
inc(k,1,n)ans+=d[k];
}
_ans=n*m*p;
ll t=__gcd(ans,_ans);ans/=t;_ans/=t;
if(_ans==1)printf("Case #%d: %lld\n",++ca,ans);else printf("Case #%d: %lld/%lld\n",++ca,ans,_ans);
}
return 0;
}