【高斯消元】兼 【期望dp】例题
【總覽】
高斯消元基本思想是將方程式的系數(shù)和常數(shù)化為矩陣,通過將矩陣通過行變換成為階梯狀(三角形),然后從小往上逐一求解。
如:$3X_1 + 2X_2 + 1X_3 = 3$
$ ? ? ? ? ? ? ?X_2 + 2X_3 = 1$
$2X_1 + X_3 = 0$
化為矩陣為:--->----->----->
然后就可以通過最后一行直接求出$X_3 = ...$,將其帶回第二行,算出$X_2$,同理算出$X_1$。
代碼很好理解:
inline void gauss(){int i, j, k, l;for(i = 1; i <= n; i++){l = i;for(j = i + 1; j <= n; j++)if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;if(l != i) for(j = i; j <= n + 1; j++)swap(matrix[i][j], matrix[l][j]);for(j = i + 1; j <= n; j++){double tmp = matrix[j][i] / matrix[i][i];for(k = i; k <= n + 1; k++)matrix[j][k] -= matrix[i][k] * tmp;}}for(i = n; i >= 1; i--){double t = matrix[i][n + 1];for(j = n; j > i; j--)t -= ans[j] * matrix[i][j];ans[i] = t / matrix[i][i];} }?高斯消元最常應(yīng)用在 ?期望DP ?中。下面是幾道例題。
“期望dp講解及例題”
【BZOJ1013】球形空間產(chǎn)生器sphere
由給出的$n + 1$個(gè)坐標(biāo),可以列出 $n$個(gè)方程,剩下的模板。
【CODE】
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std;const int N = 20; double matrix[N][N], last[N], t, ans[N]; int n;inline int read(){int i = 0, f = 1; char ch = getchar();for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());if(ch == '-') f = -1, ch = getchar();for(; ch >= '0' && ch <= '9'; ch = getchar())i = (i << 3) + (i << 1) + (ch -'0');return i * f; }inline void wr(int x){if(x < 0) putchar('-'), x = -x;if(x > 9) wr(x / 10);putchar(x % 10 + '0'); }inline void gauss(){int i, j, l, k;for(i = 1; i <= n; i++){l = i;for(j = i + 1; j <= n; j++) if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;if(l != i) for(j = i; j <= n + 1; j++)swap(matrix[i][j], matrix[l][j]);for(j = i + 1; j <= n; j++){double tmp = matrix[j][i] / matrix[i][i];for(k = i; k <= n + 1; k++) matrix[j][k] -= matrix[i][k] * tmp;}}for(i = n; i >= 1; i--){double tmp = matrix[i][n + 1];for(j = n; j > i; j--)tmp -= ans[j] * matrix[i][j];ans[i] = tmp / matrix[i][i];} }int main(){n = read();for(int i = 1; i <= n; i++) scanf("%lf", &last[i]);for(int i = 1; i <= n; i++){t = 0;for(int j = 1; j <= n; j++){double tmp; scanf("%lf", &tmp);matrix[i][j] = 2 * (tmp - last[j]);t += tmp * tmp - last[j] * last[j];last[j] = tmp;}matrix[i][n + 1] = t;}gauss();for(int i = 1; i <= n; i++){if(i < n) printf("%.3lf ", ans[i]);else printf("%.3lf\n", ans[i]);}return 0; }【BZOJ3143】游走
因?yàn)橐笃谕淖钚≈?#xff0c;那么走的次數(shù)多的邊肯定要讓花費(fèi)(編號)盡可能小,所以可以先求出從每個(gè)點(diǎn)出發(fā)次數(shù)的期望值$E_i$,那么對于一條邊而言,走這條邊的期望次數(shù)就是$E_i / degree[i] + E_j / degree[j]$,只要排一遍序就好。
求點(diǎn)的期望:$E_i = \sum (E_{son[i]} / degree[i])$
【code】
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #define eps 1e-10 using namespace std;const int N = 600; double matrix[N][N], ans[N], ret; int n, m, num, degree[N]; int st[500000], ed[500000]; double gg[500000];inline void addEdge(const int &u, const int &v){degree[u]++;degree[v]++;st[++num] = u, ed[num] = v; }inline int read(){int i = 0, f = 1; char ch = getchar();for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());if(ch == '-') f = -1, ch = getchar();for(; ch >= '0' && ch <= '9'; ch = getchar())i = (i << 3) + (i << 1) + (ch -'0');return i * f; }inline void gauss(){int i, j, l, k;for(i = 1; i <= n; i++){l = i;for(j = i + 1; j <= n; j++) if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;if(l != i) for(j = i; j <= n + 1; j++)swap(matrix[i][j], matrix[l][j]);for(j = i + 1; j <= n; j++){double tmp = matrix[j][i] / matrix[i][i];for(k = i; k <= n + 1; k++) matrix[j][k] -= matrix[i][k] * tmp;}}for(i = n; i >= 1; i--){double tmp = matrix[i][n + 1];for(j = n; j > i; j--)tmp -= ans[j] * matrix[i][j];ans[i] = tmp / matrix[i][i];} }inline bool cmp (double a, double b){return a > b; }int main(){n = read(), m = read();for(int i = 1; i <= m; i++){int u = read(), v = read();addEdge(u, v);}int i, j;for(i = 1; i <= m; i++){matrix[st[i]][ed[i]] += 1.0 /degree[ed[i]];matrix[ed[i]][st[i]] += 1.0 /degree[st[i]];}for(i = 1; i <= n; i++) matrix[n][i] = 0; for(i = 1; i <= n; i++) matrix[i][i] = -1.0;matrix[1][n + 1] = -1.0;gauss();for(i = 1; i <= m; i++)gg[i] = ans[st[i]] / degree[st[i]] + ans[ed[i]] / degree[ed[i]];sort(gg + 1, gg + m + 1, cmp);for(i = 1; i <= m; i++) ret += gg[i] * i;printf("%.3f\n", ret);return 0; }?【bzoj2337】XOR和路徑
學(xué)到了!看見求異或和$----->$按位計(jì)算:即一位一位的計(jì)算答案每一位上為1的期望值,這樣就可以輕松統(tǒng)計(jì)出答案。
每一位都要重新構(gòu)造矩陣求期望,設(shè)$a[i]$表示從$i$到$n$的路徑異或和(這一位)為$1$的期望概率(總是≤$1$)
對于當(dāng)前第$i + 1$位,若$(dis >> i) \& 1$(這一位為1),那么要異或和為$1$,要求他從關(guān)聯(lián)點(diǎn)異或和為$0$轉(zhuǎn)移來,
同理,若這一位為$0$,要求從$1$轉(zhuǎn)移來。即:$$a[i] = \sum a[son[i]](dis這一位為0) / degree[i] ?+ \sum a[son[i]](dis這一位為1) / degree[i]$$。
【code】
#include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cmath> using namespace std;const int N = 105, M = 10005; int n, m; int ecnt, st[M << 1], ed[M << 1], len[M << 1], degree[N]; double matrix[N][N], ans[N], ret;inline void addEdge(const int &u, const int &v, const int &l){st[++ecnt] = u, ed[ecnt] = v, len[ecnt] = l; degree[u]++;if(u != v) st[++ecnt] = v, ed[ecnt] = u, len[ecnt] = l, degree[v]++; }inline void gauss(){int i, j, k, l;for(i = 1; i <= n; i++){l = i;for(j = i + 1; j <= n; j++)if(fabs(matrix[j][i]) > fabs(matrix[l][i])) l = j;if(l != i) for(j = i; j <= n + 1; j++)swap(matrix[i][j], matrix[l][j]);for(j = i + 1; j <= n; j++){double tmp = matrix[j][i] / matrix[i][i];for(k = i; k <= n + 1; k++)matrix[j][k] -= matrix[i][k] * tmp;}}for(i = n; i >= 1; i--){double t = matrix[i][n + 1];for(j = n; j > i; j--)t -= ans[j] * matrix[i][j];ans[i] = t / matrix[i][i];} }int main(){scanf("%d%d", &n, &m);int i, j, k;for(i = 1; i <= m; i++){int u, v, w; scanf("%d%d%d", &u, &v, &w);addEdge(u, v, w);}for(i = 0; i <= 30; i++){memset(matrix, 0, sizeof matrix);memset(ans, 0, sizeof ans);for(j = 1; j <= n; j++) matrix[j][j] = 1;for(j = 1; j <= ecnt; j++){int l = len[j], u = st[j], v = ed[j];if(u == n) continue;if((l >> i) & 1){matrix[u][v] += 1.0 / degree[u];matrix[u][n + 1] += 1.0 / degree[u];}else matrix[u][v] -= 1.0 / degree[u];}gauss();ret += ans[1] * (1 << i);}printf("%.3f\n", ret);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/CzYoL/p/7226719.html
總結(jié)
以上是生活随笔為你收集整理的【高斯消元】兼 【期望dp】例题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图解Java内存区域及内存溢出异常
- 下一篇: stm32 输出PWM