luogu P3211 [HNOI2011]XOR和路径

题目描述

给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数。试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。

直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到 N 号节点为止,便得到一条从 1 号节点到 N 号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR 和”的期望值。

输入输出格式

输入格式:

从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N,0≤w≤109),表示该图的一条边(u,v),其权值为w。输入的数据保证图连通,30%的数据满足N≤30,100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。

输出格式:

输出文件 output.txt 仅包含一个实数,表示上述算法得到的路径的“XOR 和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算)

Sol:

好题……

我们知道Gauss消元的经典应用就是无向图DP

数据范围N<=100 ok高斯消元

然后异或没有办法直接加减之类的就选择按位做

对于每一位做出期望然后×(1<<k)加起来就行

于是后面对于每一位做的时侯图就变成只有0/1边

初始递推式子是f[i]表示i->n的期望值

所以根据异或的定义 

(∑u->v∈E) f[v]  = f[u] / du[u] (cst[i] == 0) 

(∑u->v∈E) f[v] = (1-f[u]) / du[u] (cst[i]==1)

高斯消元的时候就转化一下 未知数还是老套路dp[i]为第i个未知数就OK

每次的答案就是a[1][n+1](注意不是ans[1])

注意无向图自环特判 不然会加两次(样例还是比较良心的)

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<queue>
 6 #include<vector>
 7 #define ms(a,b) memset(a,b,sizeof a)
 8 #define rep(i,a,n) for(int i = a;i <= n;i++)
 9 #define per(i,n,a) for(int i = n;i >= a;i--)
10 #define inf 2147483647
11 using namespace std;
12 typedef long long ll;
13 ll read() {
14     ll as = 0,fu = 1;
15     char c = getchar();
16     while(c < '0' || c > '9') {
17         if(c == '-') fu = -1;
18         c = getchar();
19     }
20     while(c >= '0' && c <= '9') {
21         as = as * 10 + c - '0';
22         c = getchar();
23     }
24     return as * fu;
25 }
26 const int N = 105;
27 const int M = 20005;
28 typedef double D;
29 #define eps 1e-7
30 //head
31 int n,m;
32 int head[N],nxt[M],cst[M],mo[M],cnt;
33 int du[N];
34 void _add(int x,int y,int w) {
35     mo[++cnt] = y;
36     cst[cnt] = w;
37     nxt[cnt] = head[x];
38     head[x] = cnt;
39 }
40 void add(int x,int y,int w) {
41     if(x^y) _add(x,y,w), _add(y,x,w),du[x]++,du[y]++;
42     else _add(x,x,w),du[x]++;
43 }
44 
45 D a[N][N],ans[N];
46 D Ans;
47 void Gauss() {
48     rep(i,1,n) {
49         int maxx = i;
50         rep(j,i+1,n) if(fabs(a[j][i]) > fabs(a[maxx][i])) maxx = j;
51         if(maxx ^ i) swap(a[maxx],a[i]);
52         D div = a[i][i];
53         rep(j,i,n+1) a[i][j] /= div;
54         rep(j,1,n) {
55             if(j == i || !a[j][i]) continue;
56             div = a[j][i];
57             rep(k,i,n+1) a[j][k] -= div * a[i][k];
58         }
59     }
60 }
61 //这里就是上面求f[]的式子移项一下
62 void init(int k) {
63     ms(a,0);
64     rep(x,1,n-1) {
65         a[x][x] = 1.0;
66         for(int i = head[x]; i; i = nxt[i]) {
67             int sn = mo[i];
68             if(cst[i] & (1<<k)) {
69                 a[x][sn] += 1.0/du[x];
70                 a[x][n+1] += 1.0/du[x];
71             } else a[x][sn] -= 1.0/du[x];
72         }
73     }
74     a[n][n] = 1.0;
75     return;
76 }
77 
78 int main() {
79     n = read();
80     m = read();
81     rep(i,1,m) {
82         int x = read(),y = read(),w = read();
83         add(x,y,w);
84     }
85     rep(i,0,30) {
86         init(i);
87         Gauss();
88         Ans += a[1][n+1] * D(1<<i);//所有点到n的期望和
89     }
90     printf("%.3lf
",Ans);
91     return 0;
92 }

稳妥

> 别忘了 总有人在等着你
原文地址:https://www.cnblogs.com/yuyanjiaB/p/9736736.html