ZOJ 2794 Just Pour the Water 【矩阵快速幂】

给你n个杯子,每次有特定的到水规则,倒m次请问最后每个被子里还有多少水

我们很容易发现每次变化的规则相同,那么可以set 一个矩阵存放

然后多次倒水就相当于矩阵相乘,在m 范围达到(1<= M <= 1,000,000,000) 的情况下使用矩阵快速幂再好不过

 

这到题目注意的一点是,得使用Double 变量,如果使用FLoat会导致Wrong Answer

Source Code:

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#define Max(a,b) (((a) > (b)) ? (a) : (b))
#define Min(a,b) (((a) < (b)) ? (a) : (b))
#define Abs(x) (((x) > 0) ? (x) : (-(x)))
#define MOD 1000000007
#define pi acos(-1.0)

using namespace std;

typedef long long           ll      ;
typedef unsigned long long  ull     ;
typedef unsigned int        uint    ;
typedef unsigned char       uchar   ;

template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;}

const double eps = 1e-7      ;
const int N = 22             ;
const int M = 1100011*2      ;
const ll P = 10000000097ll   ;
const int MAXN = 100000      ;
const int INF = 0x3f3f3f3f   ;
const int MAX = 10500        ;

double a[22];
int n, m;

struct Mat {
    double mat[N][N];
};

Mat operator * (Mat a, Mat b){
    Mat c;
    memset(c.mat, 0, sizeof(c.mat));
    for(int k = 1; k <= n; ++k){
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= n; ++j){
                c.mat[i][j] += a.mat[i][k] * b.mat[k][j];
            }
        }
    }
    return c;
}

Mat operator ^ (Mat a, int k){
    Mat c;
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            c.mat[i][j] = (i == j); //init
        }
    }
    for(; k; k >>= 1){
        if(k & 1)   c = c * a;
        a = a * a;
    }
    return c;
}

int main(){
    std::ios::sync_with_stdio(false);
    int i, j, t, k, u, v, x, y, numCase = 0;
    int num;
    cin >> t;
    while(t--){
        Mat real;
        memset(real.mat, 0, sizeof(real.mat));
        cin >> n;
        for(i = 1; i <= n; ++i){
            cin >> a[i];
        }
        for(i = 1; i <= n; ++i){
            cin >> k;
            real.mat[i][i] = (double)1;
            for(j = 1; j <= k; ++j){
                cin >> num;
                real.mat[i][num] += (double)1 / (double)k;
                real.mat[i][i] -= (double)1 / (double)k;
            }
        }
        cin >> m;

        real = real ^ m;

        double ans[22];
        memset(ans, 0, sizeof(ans));
        for(i = 1; i <= n; ++i){
            for(j = 1; j <= n; ++j){
                ans[j] += a[i] * real.mat[i][j];
            }
        }
        for(i = 1; i <= n; ++i){
            if(i != n){
                printf("%.2f ",ans[i]);
            } else{
                printf("%.2f\n",ans[i]);
            }
        }
    }

    return 0;
}

 

posted @ 2015-03-08 20:00  Jeremy Wu  阅读(163)  评论(0编辑  收藏  举报