poj-3735-Training little cats-矩陣快速冪

Link:http://poj.org/problem?id=3735

Training little cats

Time Limit: 2000MS      Memory Limit: 65536K
Total Submissions: 11954        Accepted: 2951

Description

     Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to make the cats to do some exercises. Facer has well designed a set of moves for his cats. He is now asking you to supervise the cats to do his exercises. Facer's great exercise for cats contains three different moves:
    g i : Let the ith cat take a peanut.
    e i : Let the ith cat eat all peanuts it have.
    s i j : Let the ith cat and jth cat exchange their peanuts.
    All the cats perform a sequence of these moves and must repeat it m times! Poor cats! Only Facer can come up with such embarrassing idea. 
    You have to determine the final number of peanuts each cat have, and directly give them the exact quantity in order to save them.

Input

    The input file consists of multiple test cases, ending with three zeroes "0 0 0". For each test case, three integers n, m and k are given firstly, where n is the number of cats and k is the length of the move sequence. The following k lines describe the sequence.
    (m≤1,000,000,000, n≤100, k≤100)

Output

    For each test case, output n numbers in a single line, representing the numbers of peanuts the cats have.

Sample Input

3 1 6
g 1
g 2
g 2
s 1 2
g 3
e 2
0 0 0

Sample Output

2 0 1

Source

PKU Campus 2009 (POJ Monthly Contest – 2009.05.17), Facer

思路:

    這個題我們看到m非常大,並且應該是牽涉到線性變化的,故我們自然而然的聯想到矩陣快速冪,但是這個題比較難的便是矩陣的構造,因爲一開始有n個小貓,我們可以想到nXn的矩陣,那麼對於每個小貓有用的是1Xn矩陣,但是這樣的話初始是矩陣爲零矩陣,無法使用矩陣乘法由此我們修改矩陣爲(n+1)X(n+1)矩陣,我們以此題測試數據爲例。
    我們默認從0開始!!!!!——————!!!!!
    開始時
    |1 0 0 0|
    |0 0 0 0|
    |0 0 0 0|
    |0 0 0 0|
    我們找一個單位矩陣,用於記錄變換
    |1 0 0 0|
    |0 1 0 0|
    |0 0 1 0|
    |0 0 0 1|
    如果給第一隻小貓一個peanut的話變換矩陣變成
    |1 1 0 0|
    |0 1 0 0|
    |0 0 1 0|
    |0 0 0 1|
    連續給第二個小貓兩次的話則依次爲
    |1 1 1 0|
    |0 1 0 0|
    |0 0 1 0|
    |0 0 0 1|

    |1 1 2 0|
    |0 1 0 0|
    |0 0 1 0|
    |0 0 0 1|

    交換1,2小貓的peanut則相當於變換矩陣的對應1列和2列交換
    |1 2 1 0|
    |0 0 1 0|
    |0 1 0 0|
    |0 0 0 1|
    清空2貓的peanut則相當於變換矩陣的2列化爲0
    |1 1 0 0|
    |0 1 0 0|
    |0 0 0 0|
    |0 0 0 1|
    綜上a貓加一個peanut,變換矩陣M0a++;
    a貓清空peanut,變換矩陣a列化爲0;
    a,b貓交換,a列與b列值交換

    本題另一個精彩部分就是對於稀疏矩陣的乘法

代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn(105);
int n;
struct matrix
{
    long long mat[maxn][maxn];
    void zero()
    {
        for(int i=0; i<=n; i++)
        {
            for(int j=0; j<=n; j++)
            {
                this->mat[i][j]=0;
            }
        }
    }
    void unit()
    {
        zero();
        for(int i=0; i<=n; i++)
            this->mat[i][i]=1;
    }
    matrix operator * (const matrix &a)const
    {
        matrix res;
        res.zero();
        for(int k=0; k<=n; k++)
        {
            for(int i=0; i<=n; i++)
            {
                if(this->mat[i][k])
                {
                    for(int j=0; j<=n; j++)
                    {
                        res.mat[i][j]+=this->mat[i][k]*a.mat[k][j];
                    }
                }
            }
        }
        return res;
    }
    matrix operator ^(int k)const
    {
        matrix res;
        matrix B=*this;
        res.unit();
        while(k)
        {
            if(k&1)
                res=res*B;
            k>>=1;
            B=B*B;
        }
        return res;
    }

};

int main()
{
    int m,k;
    matrix start;
    matrix operation;

    while(scanf("%d%d%d",&n,&m,&k),n||m||k)
    {
        start.zero();
        start.mat[0][0]=1;
        char cmd;
        operation.unit();
        int a,b;
        while(k--)
        {
            getchar();
            cmd=getchar();
            switch(cmd)
            {
            case 'g':
                scanf("%d",&a);
                operation.mat[0][a]++;
                break;
            case 'e':
                scanf("%d",&a);
                for(int i=0; i<=n; i++)
                    operation.mat[i][a]=0;
                break;
            default:
                scanf("%d%d",&a,&b);
                for(int i=0; i<=n; i++)
                    swap(operation.mat[i][a],operation.mat[i][b]);
                break;
            }
        }
        start=start*(operation^m);
        for(int i=1; i<n; i++)
            cout<<start.mat[0][i]<<" ";
        cout<<start.mat[0][n]<<endl;
    }
    return 0;
}
發佈了37 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章