POJ 3735 Training little cats (矩阵快速幂+矩阵构造好题)

  题目:POJ 3735 Training little cats 

PS:做完了大路边上的题目,剩下的都是些难想难敲的题目了。所以看书是一方面,做题又是另一方面。这个题目给了我两个收获,

一个是代码上的优化,另一个是矩阵的非递推关系形式的构造。关于代码优化,这个题目靠普通的高代定义写法是过不去的,需要优

化,而这种写法不是从数学的角度,而是从程序优化的角度给了一种符合定义的新的写法。关键代码如下:

        for (i=1;i<=n;i++){
            for (k=1;k<=n;k++){
                if (a[i][k])for (j=1;j<=n;j++){
                    ans.a[i][j]+=a[i][k]*fun.a[k][j];
                }
            }
        }

这里把j,k调换就是定义的写法,优化了零较多的情况。

题目大意:n只猫做k个动作,循环m次,动作包括拿花生,吃花生和换花生。

解题思路:这个题目由于m很大,所以没有办法直接进行模拟,于是联想到矩阵快速幂,用连乘的方式表示状态。拿走花生,则+1,

交换等于换行,吃掉就把这一行清空(因为对之后就没有任何影响了)

ac代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstdio>
using namespace std;
struct matrix{
    long long a[110][110],n;
    matrix(long long f,long long size){
        long long i;
        n=size;
        memset (a,0,sizeof(a));
        if (f==0)return ;
        for (i=1;i<=n;i++)a[i][i]=1;
    }
    matrix operator*(const matrix&fun)const{
        matrix ans(0,n);
        long long i,j,k;
        for (i=1;i<=n;i++){
            for (k=1;k<=n;k++){
                if (a[i][k])for (j=1;j<=n;j++){
                    ans.a[i][j]+=a[i][k]*fun.a[k][j];
                }
            }
        }
        return ans;
    }
    matrix qpow(long long x)const{
        matrix ans(1,n);
        matrix tmp=(*this);
        while (x){
            if (x&1)ans=ans*tmp;
            tmp=tmp*tmp;
            x>>=1;
        }
        return ans;
    }
};
int main(){
    long long i,j,n,m,k,x,y;
    char fun;
    while (scanf("%lld%lld%lld",&n,&m,&k)!=EOF&&n+m+k){
        matrix ans(1,n+1);
        for (i=1;i<=k;i++){
            scanf("%s%lld",&fun,&x);
            if (fun=='g')ans.a[x][n+1]++;
            else if (fun=='e'){
                for (j=1;j<=n+1;j++){
                    ans.a[x][j]=0;
                }
            }
            else {
                scanf("%lld",&y);
                for (j=1;j<=n+1;j++)swap(ans.a[x][j],ans.a[y][j]);
            }
        }
        ans=ans.qpow(m);
        for (i=1;i<=n;i++){
            printf("%lld%c",ans.a[i][n+1],i==n?'\n':' ');
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值