二次联通门 : cogs 943. [東方S3] 铃仙•优昙华院•稻叶
/* cogs 943. [東方S3] 铃仙·优昙华院·稻叶 概率dp 貌似做麻烦了 邻接矩阵和链式前向星都用上了。。。 dp[pos][i][j]表示 第i秒 在i点 上一个经过的点是j 方程: dp[pos][i][j]=Σdp[pos-1][j][k]*(__out[j]+1-(map[j][k]==1))+dp[pos-1][i][j]*(__out[i]+1-(map[i][j]==1) 前面的求和考虑的是上一秒从其他的一个节点走过来 后面的考虑的是上一秒选择停留在原地 复杂度O(T * N^3) */ #include <cstdio> void read (int &now) { register char word = getchar (); for (now = 0; word < '0' || word > '9'; word = getchar ()); for (; word >= '0' && word <= '9'; now = now * 10 + word - '0', word = getchar ()); } #define Max 55 bool map[Max][Max]; int __out[Max * 200]; double dp[Max * 10][Max][Max]; int __next[Max * 200]; int __to[Max * 200]; int edge_list[Max * 200]; int Edge_Count ; inline void AddEdge (int from, int to) { Edge_Count ++; __next[Edge_Count] = edge_list[from]; __to[Edge_Count] = to; edge_list[from] = Edge_Count; } int main (int argc, char *argv[]) { freopen ("reisen.in", "r", stdin); freopen ("reisen.out", "w", stdout); int N, M, T; read (N); read (M); read (T); int x, y; for (register int i = 1; i <= M; i ++) { read (x); read (y); map[x][y] = true; __out[x] ++; AddEdge (x, y); } dp[0][1][1] = 1.00; register bool flag; for (register int pos = 0, i, j, Flan; pos <= T; pos ++) for (i = 1; i <= N; i ++) for (j = 1; j <= N; j ++) if (dp[pos][i][j] > 0.00) { flag = false; if (map[i][j]) flag = true; for (Flan = edge_list[i]; Flan; Flan = __next[Flan]) { if (__to[Flan] == j) continue; dp[pos + 1][__to[Flan]][i] += dp[pos][i][j] * 1.00 / (double)(__out[i] + !flag); } dp[pos + 1][i][j] += dp[pos][i][j] * 1.00 / (double)(__out[i] + !flag); } register double Answer; for (register int i = 1, j; i <= N; i ++) { Answer = 0.00; for (j = 1; j <= N; j ++) Answer += dp[T][i][j]; printf ("%.3lf ", Answer * 100); } return 0; }