【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径
2337: [HNOI2011]XOR和路径
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 682 Solved: 384
[Submit][Status][Discuss]
Description
几乎是一路看题解过来了。。
拖了一个星期的题目- -
已然不会概率DP(说得好像什么时候会过一样),高斯消元(打一次copy一遍)。
发现异或题目的新解决方法:按位处理。。
发现DP新方法:高斯消元。
f[k][i]代表第k位权值起点为i到终点时答案的期望值。
则对一条边<i,j>有两种转移:当边权为0,f[k][j]/deg[i].当边权为1,(1-f[k][j])/deg[i]。
由于是一个无向图。
topo DP很不好搞。
只能高斯消元。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 6 using namespace std; 7 8 struct edge{ 9 int to,c,last; 10 }edge[20001]; 11 12 int last[101],tot=0,in[101],n; 13 14 double f[120][120],V[120]; 15 16 inline int read() 17 { 18 int x=0;char ch=getchar(); 19 while(ch<'0'||ch>'9')ch=getchar(); 20 while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); 21 return x; 22 } 23 24 void add(int u,int v,int c) 25 { 26 edge[++tot].to=v,edge[tot].last=last[u],edge[tot].c=c,last[u]=tot; 27 in[u]++; 28 } 29 30 void chan(int a,int b) 31 { 32 for(int i=1;i<=n+1;i++) 33 swap(f[a][i],f[b][i]); 34 } 35 36 double gauss() 37 { 38 for(int i=1;i<=n;i++) 39 { 40 if(!f[i][i]) 41 { 42 for(int j=i+1;j<=n;j++) 43 if(f[i][j]) 44 chan(i,j); 45 } 46 for(int j=1;j<=n;j++) 47 { 48 if(i==j)continue; 49 double xi=f[j][i]/f[i][i]; 50 for(int k=1;k<=n+1;k++)f[j][k]-=xi*f[i][k]; 51 } 52 } 53 return f[1][n+1]/f[1][1]; 54 } 55 56 int main() 57 { 58 int m,u,v,c; 59 n=read(),m=read(); 60 for(int i=1;i<=m;i++) 61 { 62 u=read();v=read();c=read(); 63 add(u,v,c); 64 if(u!=v)add(v,u,c); 65 } 66 for(int i=0;i<31;i++) 67 { 68 for(int j=1;j<n;j++) 69 { 70 f[j][j]=1; 71 for(int k=last[j];k;k=edge[k].last) 72 { 73 if(edge[k].c&(1<<i))f[j][edge[k].to]+=(double)1.0/in[j],f[j][n+1]+=(double)1.0/in[j]; 74 else f[j][edge[k].to]-=(double)1.0/in[j]; 75 } 76 } 77 f[n][n]=1; 78 V[i]=gauss(); 79 memset(f,0,sizeof(f)); 80 } 81 double ans=0; 82 int cnt=1; 83 for(int i=0;i<31;i++)ans+=cnt*V[i],cnt*=2; 84 printf("%.3lf",ans); 85 return 0; 86 }