题目大意:

每条路径上有一个距离值,从1走到N可以得到一个所有经过路径的异或和,求这个异或和的数学期望

 

这道题直接去求数学期望的DP会导致很难列出多元方程组

我们可以考虑每一个二进制位从1走到N的平均概率值

因为整个图是联通的那么所有点都默认会处于多元方程组中

Pi = p[i] * sigma( v&d[i][j]?(1-Pj):Pj)

v是当前二进制位代表的数值

这里需要注意的是自环的加边情况,自环只加一次边,不能向平时那样加无向边一样

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <queue>
  7 using namespace std;
  8 const int N = 205;
  9 const int M = 10005;
 10 #define eps 1e-8
 11 int first[N] , k , degree[N] , n , m;
 12 double p[N] , a[N][N];
 13 
 14 void debug()
 15 {
 16     for(int i=0 ; i<n ; i++){
 17         for(int j=0 ; j<=n ; j++)
 18             cout<<a[i][j]<<" ";
 19         cout<<endl;
 20     }
 21 }
 22 
 23 struct Edge{
 24     int y , next , d;
 25     Edge(int y=0 , int next=0 , int d=0):y(y),next(next),d(d){}
 26 }e[M<<1];
 27 
 28 void add_edge(int x,int y,int d)
 29 {
 30     e[k] = Edge(y , first[x] , d);
 31     first[x] = k++;
 32 }
 33 
 34 int get_width(int x)
 35 {
 36     int ret =0 ;
 37     while(x)
 38     {
 39         x>>=1;
 40         ret++;
 41     }
 42     return ret;
 43 }
 44 
 45 void build(int v)
 46 {
 47     memset(a , 0 , sizeof(a));
 48     for(int i=0 ; i<n ; i++){
 49         a[i][i] = 1;
 50         if(i==n-1) continue;
 51         for(int j=first[i] ; ~j ; j=e[j].next){
 52             int u = e[j].y;
 53             if(v&e[j].d){
 54                 a[i][u] += p[i];
 55                 a[i][n] += p[i];
 56             }else{
 57                 a[i][u] -= p[i];
 58             }
 59         }
 60     }
 61    // debug();
 62 }
 63 
 64 int gauss(int n)
 65 {
 66     int i,j,k;
 67     for(i=0 , j=0 ; i<n&&j<n ; j++){
 68         for(k=i ; k<n ; k++)
 69             if(fabs(a[k][j])>eps) break;
 70         if(k<n){
 71             if(i!=k)
 72                 for(int r=j ; r<=n ; r++) swap(a[i][r],a[k][r]);
 73             double tt = 1.0/a[i][j];
 74             for(int r=j ; r<=n ; r++) a[i][r] *= tt;
 75             for(int r=0 ; r<n ; r++){
 76                 if(r == i) continue;
 77                 for(int t=n ; t>=j ; t--)
 78                     a[r][t] -= a[i][t]*a[r][j];
 79             }
 80             i++;
 81         }
 82     }
 83     for(int r=i ; r<n ; r++)
 84         if(fabs(a[r][n])>eps) return 0;
 85     return 1;
 86 }
 87 
 88 int main()
 89 {
 90     #ifndef ONLINE_JUDGE
 91         freopen("a.in" , "r" , stdin);
 92     #endif // ONLINE_JUDGE
 93     while(~scanf("%d%d" , &n , &m))
 94     {
 95         memset(first , -1 , sizeof(first));
 96         memset(degree , 0 , sizeof(degree));
 97         k = 0;
 98         int maxn = 0;
 99         for(int i=0 ; i<m ; i++){
100             int x,y,d;
101             scanf("%d%d%d" , &x , &y , &d);
102             add_edge(x-1,y-1,d);
103             if(x!=y){
104                 add_edge(y-1 , x-1 , d);
105                 degree[x-1]++ , degree[y-1]++;
106             }
107             else degree[x-1]++;
108             maxn = max(maxn , d);
109         }
110         for(int i=0 ; i<n ; i++) p[i] = 1.0/(degree[i]*1.0);//得到从当前点每条边出发的概率
111         int len = get_width(maxn);
112         double ret= 0;
113         for(int i=0 ; i<len ; i++){
114             int v = 1<<i;
115             build(v);
116             gauss(n);
117             ret += v*a[0][n];
118         }
119         printf("%.3f\n" , ret);
120     }
121     return 0;
122 }

 

 posted on 2015-05-28 13:10  Love风吟  阅读(205)  评论(0编辑  收藏  举报