题目链接
大意:有个无向图,你从1出发,可以到任意联通的非怪物点,你至多可以选择一个可达的怪物房间使用魔法,传送到随机一个与怪物点相邻的点上,问你取得糖果的期望值(操作者足够聪明)。
思路:我们先dfs记录一下,不到怪物房间就能取到的糖果数量,这一部分肯定是可以直接拿的,剩下就是从那些相邻(意为不用经过怪物房间就能到的怪物房间)的怪物房间取一个最优的。
这个最优也是dfs记录从当前怪物点出发,随机下一个儿子,dfs计算能取到的糖果数量(同上面的dfs一样,不遇到怪物)加起来,除以儿子数量。
注意中间要记录访问过的点,不然会段错误哦。
细节见代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define LL long long
#define pii pair<int,int>
#define SZ(x) (int)x.size()
#define all(x) x.begin(),x.end()
using namespace std;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
const int N = 1e6 + 3;
const LL mod = 1e9 + 7;
int t,n,m,k;
int c[N];
vector<int>v[N],q;
int vis[N],ans;
void dfs(int now,int pre){
vis[now]=1;
ans++;
for(auto k:v[now]){
if(k==pre||vis[k])continue;
if(c[k])vis[k]=1,q.pb(k);
else{
dfs(k,now);
}
}
}
vector<int>res;
int mid[N];
int bfs(int now,int pre){
int ans=1;
mid[now]=1;
res.pb(now);
for(auto k:v[now]){
if(k==pre||c[k]||vis[k]||mid[k])continue;
ans+=bfs(k,now);
}
return ans;
}
int main() {
for(scanf("%d",&t);t;t--){
q.clear();
scanf("%d%d%d",&n,&m,&k);ans=0;
for(int i=1;i<=n;i++)v[i].clear(),c[i]=0,vis[i]=0,mid[i]=0;
for(int i=1;i<=m;i++){
int s,t;
scanf("%d%d",&s,&t);
v[s].pb(t);
v[t].pb(s);
}
for(int i=1;i<=k;i++){
int s;
scanf("%d",&s);
c[s]=1;
}
dfs(1,0);
LL tot=0;
double ANS=ans;
for(auto k:q){
tot=0;
int sz=SZ(v[k]);
if(!sz)continue;
for(auto ne:v[k]){
res.clear();
if(vis[ne]||c[ne])continue;
tot+=bfs(ne,k);
for(auto X:res)mid[X]=0;
}
double res=1.0*tot/sz;
ANS=max(ANS,res+ans);
}
printf("%.6f\n",ANS);
}
return 0;
}