[LA 6607 Traveling Fool] 倍增逼近概率

题目

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;
}


你可能感兴趣的:([LA 6607 Traveling Fool] 倍增逼近概率)