HDU 4443 带环树形dp

时间:2023-03-09 20:14:19
HDU 4443  带环树形dp

思路:如果只有一棵树这个问题很好解决,dp一次,然后再dfs一次往下压求答案就好啦,带环的话,考虑到环上的点不是

很多,可以暴力处理出环上的信息,然后最后一次dfs往下压求答案就好啦。细节比较多。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define PLI pair<LL, int>
#define ull unsigned long long
using namespace std; const int N = 1e5 + ;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + ;
const double eps = 1e-; double ans[N], dp[N], up[N], down[N];
int n, m, tot, head[N], deg[N], edgecnt[N];
bool is[N], vis[N];
vector<int> cir;
struct Edge {
int from, to, nx;
} edge[N<<]; void addEdge(int u, int v) {
edge[tot].from = u;
edge[tot].to = v;
edge[tot].nx = head[u];
head[u] = tot++;
}
void dfs(int u) {
vis[u] = true;
cir.push_back(u);
for(int i = head[u]; ~i; i = edge[i].nx) {
int v = edge[i].to;
if(is[v] || vis[v]) continue;
dfs(v);
}
} void dfs1(int u, int fa) {
edgecnt[u] = ;
for(int i = head[u]; ~i; i = edge[i].nx) {
if(edge[i].to == fa || !is[edge[i].to]) continue;
int v = edge[i].to;
edgecnt[u]++;
dfs1(v, u);
}
dp[u] = 1.0 / (edgecnt[u]+);
if(edgecnt[u]) {
for(int i = head[u]; ~i; i = edge[i].nx) {
if(edge[i].to == fa || !is[edge[i].to]) continue;
int v = edge[i].to;
dp[u] += dp[v] / edgecnt[u];
}
}
} void dfs2(int u, int fa, double val) {
if(!edgecnt[u]) {
ans[u] += val;
return;
}
double sum = ;
for(int i = head[u]; ~i; i = edge[i].nx) {
if(edge[i].to == fa || !is[edge[i].to]) continue;
sum += dp[edge[i].to];
}
if(!fa) {
for(int i = head[u]; ~i; i = edge[i].nx) {
if(edge[i].to == fa || !is[edge[i].to]) continue;
int v = edge[i].to;
if(edgecnt[u] == ) dfs2(v, u, 1.0/(edgecnt[u]+)+val);
else dfs2(v, u, 1.0/(edgecnt[u]+)+val/edgecnt[u]+(sum-dp[v])/(edgecnt[u]+));
}
} else {
for(int i = head[u]; ~i; i = edge[i].nx) {
if(edge[i].to == fa || !is[edge[i].to]) continue;
int v = edge[i].to;
dfs2(v, u, 1.0/(edgecnt[u]+)+val/edgecnt[u]+(sum-dp[v])/edgecnt[u]);
}
}
} void init() {
tot = ; cir.clear();
for(int i = ; i <= n; i++)
head[i]=-, ans[i]=deg[i]=is[i]=vis[i]=;
} int main() {
while(scanf("%d", &n) != EOF && n) {
init();
for(int i = ; i <= n; i++) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v); addEdge(v, u);
deg[u]++, deg[v]++;
}
queue<int> que;
for(int i = ; i <= n; i++) {
if(deg[i] == ) {
que.push(i);
is[i] = true;
}
}
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nx) {
int v = edge[i].to;
if(is[v]) continue;
deg[v]--, deg[u]--;
if(deg[v] == ) {
is[v] = true;
que.push(v);
}
}
} for(int i = ; i <= n; i++)
if(!is[i] && !vis[i]) dfs(i); int cnt = cir.size();
for(int i = ; i < cnt; i++) {
int root = cir[i];
dfs1(root, );
up[root] = 1.0*/(edgecnt[root]+); down[root] = ;
for(int j = head[root]; ~j; j = edge[j].nx) {
int v = edge[j].to;
if(!is[v]) continue;
up[root] += dp[v]*/(edgecnt[root]+);
}
} for(int i = ; i < cnt; i++) {
double now = up[cir[i]]/;
for(int k = ; k < cnt; k++) {
int j = (i+k)%cnt;
if(k == cnt-) down[cir[j]] += now;
else down[cir[j]] += now*(edgecnt[cir[j]])/(edgecnt[cir[j]]+);
now /= edgecnt[cir[j]]+;
}
now = up[cir[i]]/;
for(int k = ; k < cnt; k++) {
int j = (i-k+cnt)%cnt;
if(k == cnt-) down[cir[j]] += now;
else down[cir[j]] += now*(edgecnt[cir[j]])/(edgecnt[cir[j]]+);
now /= edgecnt[cir[j]]+;
}
}
for(int i = ; i < cnt; i++)
dfs2(cir[i], , down[cir[i]]); sort(ans+, ans++n);
reverse(ans+, ans++n);
double ret = ;
for(int i = ; i <= ; i++)
ret += ans[i];
printf("%.5f\n", ret/n);
}
return ;
} /*
*/