2011-06-13 22:23:43Morris

d769. 共有多少種走法?

http://zerojudge.tw/ShowProblem?problemid=d769

內容 :

-------不想廢話了--------
給定一個有N個點的單向無權圖(編號1~N),請問從點i走k步後到點j共有多少種走法呢?

輸入說明 :

每組測資的第一行給定節點數N及步數k
接下來好多行敘述此單向圖,
每一行的x y s代表從點x直達點y共有s條路徑,而每條路徑都是一步到達
以0 0 0代表此圖敘述結束
例如第一組範例測資:
3 3
1 2 2
2 1 1
2 3 4
2 2 1
3 1 2
0 0 0

代表從點1到點2共有2條路徑直達
注意2 2 1代表點2到點2有1條路徑,是合法輸入
若有未敘述到的代表那兩點間直達路徑數是0
測資保證不會有重覆輸入或不合法的節點編號出現

然後輸入詢問數Q,代表有Q行詢問
接下來Q行各有兩個數i j,請對每一組i j 輸出從i出發,走k步剛好到達j共有多少種走法
另外因為答案可能好大,所以請輸出 mod 5281的答案

注意途中可以先經過j沒關係,只要第k步能剛好到達j就行了
走過的路徑都可以再走。
範圍: 1<=N<=50,Q<=N2,0<=s<=20,1<=k<=10000000

輸出說明 :

對每一個詢問i j
輸出從i出發,走k步剛好到達j共有多少種走法 mod 5281的答案

範例輸入 :

3 3
1 2 2
2 1 1
2 3 4
2 2 1
3 1 2
0 0 0
9
1 2
1 1
2 1
1 3
2 2
2 3
3 1
3 2
3 3
2 4
1 1 1
1 2 3
2 1 5
0 0 0
3
1 1
1 2
2 1

範例輸出 :

6
18
11
8
21
12
4
4
16
271
93
155

提示 :

O(N3logk)

出處 :

國文課時的靈機一動(誤 (管理:david942j)



作法 : 與上題雷同,矩陣乘法 & D&C
加速的方法,減少%的運算量,算一算乘完(5281*5281*N < int)
整個再說%即可
不會在途中爆掉

/**********************************************************************************/
/*  Problem: d769 "共有多少種走法?" from 國文課時的靈機一動(誤   */
/*  Language: C                                                                   */
/*  Result: AC (412ms, 364KB) on ZeroJudge                                        */
/*  Author: morris1028 at 2011-06-12 08:21:20                                     */
/**********************************************************************************/


#include<stdio.h>
typedef struct {
    int t[50][50];
}Matrix;
Matrix A, In, init;
Matrix mult(Matrix x, Matrix  y, int n) {
    Matrix t = init;
    int i, j, k;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            for(k = 0; k < n; k++) {
                t.t[i][k] += x.t[i][j]*y.t[j][k];
            }
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            t.t[i][j] %= 5281;
    return t;
}
int ans(int k, int n) {
    Matrix x = In, y = A;
    while(k) {
        if(k&1) x = mult(x, y, n);
        y = mult(y, y, n);
        k /= 2;
    }
    int Q, i, j;
    scanf("%d", &Q);
    while(Q--) {
        scanf("%d %d", &i, &j);
        printf("%d\n", x.t[i-1][j-1]);
    }
}
main() {
    int n, a, b, k, x, y, s;
    while(scanf("%d %d", &n, &k) == 2) {    
        for(a = 0; a < n; a++)
            for(b = 0; b < n; b++)
                A.t[a][b] = 0, In.t[a][b] = 0,
                init.t[a][b] = 0;
        for(a = 0; a < n; a++) In.t[a][a] = 1;
        while(scanf("%d %d %d", &x, &y, &s) == 3) {
            if(x + y + s == 0) break;
            A.t[x-1][y-1] += s;
        }
        ans(k, n);
    }
    return 0;
}