题目
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=599&page=show_problem&problem=4618
分析
倍增逼近概率
设f[k][i][j]表示走了2k步,从i到j的形成回文的概率,那么
f[k][i][j]=f[k-1][x][y]/(deg[i]*deg[y]),x是i的后继,j是y的后继且(i,x)与(y,j)颜色相同
边界:f[0][i][i]=1,f[0][i][j]=1/deg[i],(i,j)存在
答案是sigma{f[k][s][t]}
构造一个n^2+1的矩阵自乘即可
数据较弱
代码
/************************************************** * Problem: LA 6607 * Author: clavichord93 * State: Accepted **************************************************/ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int MAX_N = 15; const int MAX_S = 12 * 12 + 5; const int MAX_E = 2005; struct Edge { int dest; char color; Edge *next; Edge() {} Edge(int _dest, char _color, Edge *_next) : dest(_dest), color(_color), next(_next) {} }; int n, m; Edge EdgePool[MAX_E]; Edge *EP; Edge *e[MAX_N]; Edge *_e[MAX_N]; int deg[MAX_N]; char color[10]; double tmp[MAX_S][MAX_S]; double mat[MAX_S][MAX_S]; inline void addedge(int a, int b, char c) { e[a] = new(EP++)Edge(b, c, e[a]); _e[b] = new(EP++)Edge(a, c, _e[b]); deg[a]++; } void multiply() { int size = n * n + 1; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { tmp[i][j] = 0; } } for (int k = 0; k < size; k++) { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { tmp[i][j] += mat[i][k] * mat[k][j]; } } } for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { mat[i][j] = tmp[i][j]; } } } int main() { #ifdef LOCAL_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int T; scanf("%d", &T); for (int cas = 1; cas <= T; cas++) { EP = EdgePool; memset(e, 0, sizeof(e)); memset(_e, 0, sizeof(_e)); memset(deg, 0, sizeof(deg)); scanf("%d %d", &n, &m); for (int i = 0; i < m; i++) { int a, b; scanf("%d %d %s", &a, &b, color); addedge(a, b, color[0]); } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int x = i * n + j; for (Edge *p = e[i]; p; p = p->next) { for (Edge *q = _e[j]; q; q = q->next) { if (p->color == q->color) { //cout << i << ' ' << j << ' ' << p->dest << ' ' << q->dest << endl; int y = p->dest * n + q->dest; mat[x][y] += 1.0 / (deg[i] * deg[q->dest]); } } } } } mat[n * n][n * n] = 1.0; for (int i = 0; i < n; i++) { mat[i * n + i][n * n] = 1.0; for (Edge *j = e[i]; j; j = j->next) { mat[i * n + j->dest][n * n] = 1.0 / deg[i]; } } for (int i = 0; i < 32; i++) { multiply(); } int Q; scanf("%d", &Q); printf("Case %d:\n", cas); for (int i = 0; i < Q; i++) { int a, b; scanf("%d %d", &a, &b); printf("%.10f\n", mat[a * n + b][n * n]); } } return 0; }