http://acm.hdu.edu.cn/showproblem.php?pid=4035
学到:
1、先判断是不是树,其实凡是有图的感觉的,都看边数==点数-1是不是成立
2、树有时候区分老子跟孩子还是有必要的,这道题就是,不过是在dfs的时候,传参数的时候多加个表示父节点的参数而已
3、一定注意,概率DP对精度真的要求很高 开始的时候写1e-8,WA了好几发,改了1e-10 AC
4、注意分母为0的可能的时候加上判断
讲的很详细的题解:http://blog.csdn.net/morgan_xww/article/details/6776947
直接按公式写的代码就是:
#include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <iostream> #include <iomanip> #include <cmath> #include <map> #include <set> #include <queue> using namespace std; #define ls(rt) rt*2 #define rs(rt) rt*2+1 #define ll long long #define ull unsigned long long #define rep(i,s,e) for(int i=s;i<e;i++) #define repe(i,s,e) for(int i=s;i<=e;i++) #define CL(a,b) memset(a,b,sizeof(a)) #define IN(s) freopen(s,"r",stdin) #define OUT(s) freopen(s,"w",stdout) const ll ll_INF = ((ull)(-1))>>1; const double EPS = 1e-10; const int INF = 100000000; const int MAXN = 10000+100; vector<int>g[MAXN]; double k[MAXN],e[MAXN]; double a[MAXN],b[MAXN],c[MAXN]; int n; bool sea(int i, int fa) { if(g[i].size() == 1 && fa!=-1)//叶子节点 { a[i]=k[i]; c[i]=b[i]=1.0-k[i]-e[i]; return true; } //非叶子节点,此时该非叶子节点的子孙都已经遍历过了 double aa=0.0,bb=0.0,cc=0.0; for(int j=0;j<g[i].size();j++) { if( g[i][j] == fa)continue; if(!sea(g[i][j],i))return 0; aa+=a[g[i][j]]; bb+=b[g[i][j]]; cc+=c[g[i][j]]; } int m=g[i].size(); a[i]=(k[i]+(1-k[i]-e[i])/m*aa)/(1-(1.0-k[i]-e[i])/m*bb); b[i]=(1.0-k[i]-e[i])/m/(1.0-(1.0-k[i]-e[i])/m*bb); c[i]=( (1.0-k[i]-e[i])+(1.0-k[i]-e[i])/m*cc )/(1.0 -(1.0-k[i]-e[i])/m*bb); return true; } int main() { int ncase,u,v,ic=0; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); for(int i=1;i<=n;i++) g[i].clear(); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(int i=1;i<=n;i++) { scanf("%lf%lf",&k[i],&e[i]); k[i]/=100.0; e[i]/=100.0; } printf("Case %d: ",++ic); if(sea(1,-1) && fabs(1.0-a[1])>EPS) printf("%.6lf\n",c[1]/(1.0-a[1])); else printf("impossible\n"); } return 0; }
当然更好的写法还是题解上的
#include <cstdio> #include <iostream> #include <vector> #include <cmath> using namespace std; const int MAXN = 10000 + 5; double e[MAXN], k[MAXN]; double A[MAXN], B[MAXN], C[MAXN]; vector<int> v[MAXN]; bool search(int i, int fa) { if ( v[i].size() == 1 && fa != -1 ) { A[i] = k[i]; B[i] = 1 - k[i] - e[i]; C[i] = 1 - k[i] - e[i]; return true; } A[i] = k[i]; B[i] = (1 - k[i] - e[i]) / v[i].size(); C[i] = 1 - k[i] - e[i]; double tmp = 0; for (int j = 0; j < (int)v[i].size(); j++) { if ( v[i][j] == fa ) continue; if ( !search(v[i][j], i) ) return false; A[i] += A[v[i][j]] * B[i]; C[i] += C[v[i][j]] * B[i]; tmp += B[v[i][j]] * B[i]; } if ( fabs(tmp - 1) < 1e-10 ) return false; A[i] /= 1 - tmp; B[i] /= 1 - tmp; C[i] /= 1 - tmp; return true; } int main() { int nc, n, s, t; cin >> nc; for (int ca = 1; ca <= nc; ca++) { cin >> n; for (int i = 1; i <= n; i++) v[i].clear(); for (int i = 1; i < n; i++) { cin >> s >> t; v[s].push_back(t); v[t].push_back(s); } for (int i = 1; i <= n; i++) { cin >> k[i] >> e[i]; k[i] /= 100.0; e[i] /= 100.0; } cout << "Case " << ca << ": "; if ( search(1, -1) && fabs(1 - A[1]) > 1e-10 ) cout << C[1]/(1 - A[1]) << endl; else cout << "impossible" << endl; } return 0; }
时间: 2024-10-19 11:50:19