bzoj 3270 博物馆

problem:

给n个点,m条边的一个连通图,每两个点之间最多一条边,起始时x,y两个人在A,B两点,求他们在每个点相遇的概率。

n<=20

solution:

(还是逆序定义..)

定义f[i][j]为x,y分别走到i,j的期望步数

f[i][j]=∑f[q][w]* (p[q]or(1-p[q])*1/degree[q]) * (p[w]or(1-p[w])*1/degree[w]) (q为与i相连的边 w为与j相连的边  i,j包括在q,w之内  但是q,w不能相等)

特别的 f[A][B]=∑f[q][w]* (p[q]or(1-p[q])*1/degree[q]) * (p[w]or(1-p[w])*1/degree[w]) + 1

这样得到n^2个方程,高斯消元解得f[i][i](i<=n) 的期望步数,之后可以求出概率

(ps:我因为打错了高斯板子调了很长时间.............)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<cmath>
  5 #define mem(a,b) memset(a,b,sizeof(a))
  6 #define dd double
  7 using namespace std;
  8 void swap(dd &x,dd &y){dd temp=x;x=y;y=temp;}
  9 dd abss(dd x){return x<0?-x:x;}
 10 struct son
 11 {
 12     int v,next;
 13 };
 14 son a1[501];
 15 int first[501],e;
 16 void addbian(int u,int v)
 17 {
 18     a1[e].v=v;
 19     a1[e].next=first[u];
 20     first[u]=e++;
 21 }
 22 
 23 int n,m,A,B;
 24 dd p[501],deg[501];
 25 int u,o;
 26 dd a[501][501],b[501],ans[501];
 27 int ji[501][501],limit[501];
 28 int num;
 29 
 30 void gaos()
 31 {
 32     int now=1;
 33     for(int k=1;k<=num;++k,++now)
 34     {
 35         int order=now;
 36         for(int i=now+1;i<=num;++i)
 37           if(abss(a[i][k])>abss(a[order][k]))
 38             order=i;
 39         if(order!=now)
 40         {
 41             for(int j=1;j<=num;++j)
 42               swap(a[now][j],a[order][j]);
 43             swap(b[now],b[order]);
 44         }
 45         if(!a[now][k])
 46         {
 47             --now;
 48             continue;
 49         }
 50         for(int i=now+1;i<=num;++i)
 51         {
 52             dd temp=a[i][k]/a[now][k];
 53             for(int j=k;j<=num;++j)
 54               a[i][j]-=a[now][j]*temp;
 55             b[i]-=b[now]*temp;
 56         }
 57     }
 58     
 59     for(int i=num;i>=1;--i)
 60     {
 61         for(int j=num;j>i;--j)
 62           b[i]-=a[i][j]*ans[j];
 63         ans[i]=b[i]/a[i][i];
 64     }
 65 }
 66 
 67 int main(){
 68     mem(first,-1);
 69     scanf("%d%d%d%d",&n,&m,&A,&B);
 70     for(int i=1;i<=m;++i)
 71     {
 72         scanf("%d%d",&u,&o);
 73         ++deg[u];
 74         ++deg[o];
 75         addbian(u,o);
 76         addbian(o,u);
 77     }
 78     
 79     for(int i=1;i<=n;++i)
 80       addbian(i,i);
 81     
 82     for(int i=1;i<=n;++i)
 83       scanf("%lf",&p[i]);
 84     
 85     for(int i=1;i<=n;++i)
 86       for(int j=1;j<=n;++j)
 87         ji[i][j]=(i-1)*n+j;
 88     
 89     b[ji[A][B]]=-1;
 90     
 91     for(int i=1;i<=n;++i)
 92       for(int j=1;j<=n;++j)
 93       {
 94             a[++num][ji[i][j]]=-1;
 95             for(int k=first[i];k!=-1;k=a1[k].next)
 96             {
 97                 int tempk=a1[k].v;
 98                 for(int l=first[j];l!=-1;l=a1[l].next)
 99                 {
100                     int templ=a1[l].v;
101                     if(tempk==templ)continue;
102                     a[num][ji[tempk][templ]]+=(tempk==i?p[tempk]:(1.0-p[tempk])*1.0/deg[tempk]) * (templ==j?p[templ]:(1.0-p[templ])*1.0/deg[templ]);
103                 }
104             }
105         }
106     gaos();
107     dd temp=0;
108     for(int i=1;i<=n;++i)
109       temp+=ans[ji[i][i]];
110     for(int i=1;i<=n;++i)
111       printf("%.6lf ",ans[ji[i][i]]/temp);
112     //while(1);
113     return 0;
114 }
code

 

posted @ 2017-07-27 07:23  A_LEAF  阅读(210)  评论(0编辑  收藏  举报