bzoj2337期望DP-高斯消元

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<algorithm>
 7 using namespace std;
 8 namespace Moxing {
 9     int n,m;
10     struct node {
11         int to,nxt,dis;
12     } edge[20005];
13     int last[105],cnt,oud[105];
14     void add(int from,int to,int dis) {
15         edge[++cnt].to=to;
16         edge[cnt].nxt=last[from];
17         edge[cnt].dis=dis;
18         last[from]=cnt;
19     }
20     double f[105][105];
21     void gauss(){
22         int i,j,k;
23         for(i=1;i<=n;i++){
24             int p=i;
25             for(j=i+1;j<=n;j++){
26                 if(fabs(f[j][i])>fabs(f[p][i])) p=j;
27             }
28             if(p!=i) swap(f[i],f[p]);
29             for(j=i+1;j<=n;j++){
30                 double c=f[j][i]/f[i][i];
31                 for(k=i;k<=n+1;k++){
32                     f[j][k]-=f[i][k]*c;
33                 }
34             }
35         }
36         for(i=n;i;i--){
37             double res=0;
38             for(j=i+1;j<=n;j++){
39                 res+=f[j][n+1]*f[i][j];
40             }
41             f[i][n+1]=(f[i][n+1]-res)/f[i][i];
42         }
43         return ;
44     }
45     struct main {
46         main() {
47             scanf("%d%d",&n,&m);
48             for(int i=1; i<=m; i++) {
49                 int x,y,w;
50                 scanf("%d%d%d",&x,&y,&w);
51                 add(x,y,w),oud[x]++;
52                 if(x!=y) {
53                     add(y,x,w),oud[y]++;
54                 }
55             }
56             double ans=0;
57             for(int k=0; k<=30; k++) {
58                 memset(f,0,sizeof(f));
59                 for(int x=1; x<=n; x++) f[x][x]=1;
60                 for(int x=1; x<n; x++) {
61                     for(int i=last[x]; i; i=edge[i].nxt) {
62                         int y=edge[i].to;
63                         if((edge[i].dis>>k)&1) {
64                             f[x][y]+=(1.0/(double)oud[x]);
65                             f[x][n+1]+=(1.0/(double)oud[x]);
66                         } else f[x][y]-=(1.0/(double)oud[x]);
67                     }
68                 }
69                 gauss();
70                 ans+=f[1][n+1]*(1<<k);
71             }
72             printf("%.3f",ans);
73             exit(0);
74         }
75     } UniversalLove;
76 }
77 int main() {
78     Moxing::main();
79 }
View Code

f[i]为从i点到n点,XOR和为1的概率:

f[i]= ∑(w(i,j)==0)  f[j]/oud[i]   +  ∑(w(i,j)==1) (1-f[j])/oud[i]

以下内容参考:https://www.cnblogs.com/nietzsche-oier/p/8416045.html

概率/期望DP:

转移时涉及概率的DP,他可以是线性的、树上的、DAG上的、任何形式的;
其标志是转移时涉及概率,
如“状态x有p/q的概率转移到y,有(1-p/q)的概率转移到z”;
一般情况下概率/期望DP除了应该使用浮点数据类型存贮状态、可能可以通过概率有关的知识优化之外,与非概率期望DP没有什么不同;
然而又有一类概率/期望DP则不同;
即一部分DP序混乱的无向图概率/期望DP

无向图概率/期望DP:

无向图DP,这里指的是在无向图上DP
无向图概率/期望DP并非一定是DP序混乱的,然而这里只讨论DP序混乱的那一部分;
DP序混乱,往往是指存在两个状态x,y,x可以转移到y,y也可以转移到x;
在非概率/期望DP中不可能存在这种情况——因为这会导致状态值不确定;
然而在概率/期望DP中这种情况却可以存在;
因为如果在此类DP中,存在DP序混乱的情况,一般是x的p/q可以转移到y,y的a/b可以转移到x;
于是经过了无穷次相互转移后,之后的转移增量趋向于无穷小,于是可以认为此时状态的值确定了下来;
于是,有了一种十分显然的想法——迭代相互转移的次数,直到精度符合要求;
然而这种想法是十分幼稚的——迭代层数无法确定,
于是得分的上限取决于你设定的迭代层数会在什么数据范围的情况下导致超时;
得分的下限则完全取决于出题人的心情,这意味着出题人很容易造出可以卡掉迭代层数很高的代码的数据;
于是有了用高斯消元处理DP序混乱的无向图概率/期望DP方法

高斯消元:

1.选定一个未知数xi,准备把他消去;
2.随便选定一个xi系数不为零的方程Xi,(若没有,则无解或无数解);
3.把其他所有方程都减去Xi的某倍数,促使除了Xi外,所有方程的xi被消去;
4.重复123,(每个未知数,每个方程只被选定一次),直到只剩下一个未知数一个方程;
5.按选定方程的倒序选定方程,不断把已知未知数的值带入其中得到新未知数的值;
有唯一解的条件,至少n个方程,在高斯消元过程中没有被作无解或无数解

猜你喜欢

转载自www.cnblogs.com/Moxingtianxia/p/11402489.html