测试地址
题意简述:
在一个无向图中,有 k 个怪物点,n-k个糖果点,每个糖果点有1个糖果,且可以移动到相邻的点,但是每个点的糖果只能拿一次(但是可以经过多次)。而每个怪物点没糖果,但是可以随机传送到相邻的点,只能传送一次(即只能进一次怪物房),请问最终拿到糖果的最优期望是多少?
解题思路:
dfs求连通块+染色,我现在还是不明白我单独染色为什么一直超时,无语了,就按照下面的代码写吧,用标记数组单独存放被染色的连通块糖果数,相当于记忆化。当然节点1所在的连通块糖果都能拿到,然后再选择走和1相连的且期望最大的怪物点即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2e5+10;
int head[N],ver[2*N],nex[2*N],tot = 1;
int n,m,t,k;
int vis[N],mst[N];
void addEdge(int x,int y){
ver[++tot] = y;nex[tot] = head[x]; head[x] = tot;
}
int ans = 0;
int vm[N],cnt = 0;
int num[N];
int tc[N];
void dfs1(int x){
vis[x] = 1; ans++; tc[x]++;
for(int i = head[x];i != -1;i = nex[i]){
int y = ver[i];
if(vis[y]) continue;
if(mst[y]){
vm[++cnt] = y;
continue;
}
dfs1(y);
}
}
double dfs2(int x,int col){
if(num[col]) return num[col];
if(vis[x] || mst[x]) return 0;
double res = 1; vis[x] = col;
for(int i = head[x];i != -1;i = nex[i]){
int y = ver[i];
if(vis[y] || mst[y]) continue;
res += dfs2(y,col);
}
return res;
}
void solve(){
ans = 0; cnt = 0;
memset(vis,0,sizeof vis);
memset(num,0,sizeof num);
dfs1(1); double mx = 0; int col = 1;
for(int i = 1;i <= cnt;i++){
double pp = 0,ecnt = 0;
for(int j = head[vm[i]] ;j != -1;j = nex[j]) ecnt++;
//printf("ecnt: %f\n",ecnt);
for(int j = head[vm[i]] ;j != -1;j = nex[j]){
int y = ver[j]; double tmp;
if(vis[y]) tmp = num[vis[y]];
else{
tmp = dfs2(y,++col);
num[col] = tmp;
}
pp += tmp;
//printf("%d %f\n",ver[j] ,tmp);
}
pp /= ecnt;
if(mx - pp < 0) mx = pp;
}
printf("%.7f\n",mx+ans);
}
int getInt() {
int ans = 0;
bool neg = false;
char c = getchar();
while (c!='-' && (c<'0' || c>'9')) c = getchar();
if (c == '-') neg = true, c = getchar();
while (c>='0' && c<='9')
ans = ans*10 + c-'0', c = getchar();
return neg ? -ans : ans;
}
int main(){
t = getInt();
while(t--){
tot = 1;
memset(mst,0,sizeof mst);
memset(head,-1,sizeof head);
n = getInt(), m = getInt(),k = getInt();
for(int i = 1,x,y;i <= m;i++){
x = getInt(); y = getInt();
addEdge(x,y);addEdge(y,x);
}
for(int i = 1,x;i <= k;i++) x = getInt() , mst[x] = 1;
solve();
}
return 0;
}