B. Dudu’s maze
题意
给你一个无向无自环图,
l
y
ly
ly从一号点出发。
每个点上有糖果或者怪兽,如果遇到糖果他可以捡起糖果,随便走到相邻点。
如果第一次遇到怪物,他可以使用魔法,等概率随机的走向一个相邻点,如果第二次遇到怪兽,游戏结束。
ly知道地图结构,如果他每一步都走的是最佳的,问能得到的糖果数量的最大期望。
思路
这题关键是要想到联通块啊啊啊啊!!!
先把联通的糖果缩成一点。
然后枚举每一个怪兽的位置(要求他的任意一条出边的终点和1在同一联通块,相当于从1到了这个怪兽的位置,之后处理等概率随机走一条边之后就不能再遇到怪兽了,就相当于再加上了一个联通块),取一个最优值。
复杂度是可以保证的,因为最多
2
∗
n
2*n
2∗n条边,那么枚举怪兽的出边时,最多
4
∗
n
4*n
4∗n次。
并查集老WA,多半是用
i
i
i而不用
f
o
u
n
d
(
i
)
found(i)
found(i) ?
/* Author : Rshs
* Data : 2019-09-19-20.29
*/
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MX = 1e6+5;
int fa[MX];
int found(int x){
if(x==fa[x])return x;
return fa[x]=found(fa[x]);
}
vector<int>g[MX];
int q[MX],vis[MX],sa[MX],sb[MX];
bool jud(int x){ //判断是否有出边的终点和1在同一联通快
for(auto to:g[x]){
if(found(to)==found(1))return 1;
}
return 0;
}
vector<int>v[MX];int cas;
void Main(int avg){
int n,m,k;cin>>n>>m>>k;
for(int i=1;i<=n;i++) fa[i]=i,g[i].clear(),v[i].clear(),vis[i]=0;
for(int i=1;i<=m;i++){
scanf("%d %d",&sa[i],&sb[i]);
g[sa[i]].push_back(sb[i]);
g[sb[i]].push_back(sa[i]);
}
for(int i=1;i<=k;i++){
scanf("%d",&q[i]);vis[q[i]]=1;
}
for(int i=1;i<=m;i++){
if(vis[sa[i]]||vis[sb[i]])continue;
int aa=found(sa[i]),bb=found(sb[i]);
if(aa!=bb) fa[aa]=bb;
}
for(int i=1;i<=n;i++) if(!vis[i])v[found(i)].push_back(i); //注意怪兽的贡献为0
int rt=found(1);
double ans=SZ(v[rt]);
for(int i=1;i<=k;i++){
if(!jud(q[i])) continue;
double sz=SZ(g[q[i]]);
double now=0;
for(auto to:g[q[i]]){
int fto=found(to);
if(fto==rt) now=now+(double)(SZ(v[rt]))/sz; //回到1的联通块
else now=now+(double)(SZ(v[fto])+SZ(v[rt]))/sz; //去别的联通块
}
ans=max(ans,now);
}
printf("%.12lf",ans);
if(avg!=cas)puts("");
}
int main(){
cin>>cas;for(int i=1;i<=cas;i++)Main(i);
return 0;
}