专题:强大的运算工具——矩阵

16 篇文章 0 订阅
10 篇文章 0 订阅

什么是矩阵

  • 对于 矩阵的的初步认识这里有一些讲解。
  • 一开始我对矩阵奇葩的运算方式感到奇怪,它有什么用。。。
    • DP 问题的加速可以利用矩阵的结合律来实现。
    • 同时一些图论问题,利用矩阵有关图的联通和边权问题我们又有了一个新招了。(讲道理,要用到矩阵的题目似乎都是为它专门设计的。)
    • 同时还有其他的作用可以参考大牛的博客十个利用矩阵乘法解决的经典题目 code

矩阵乘法在图联通中的意义

这里写图片描述

00111000000101000011100000010100>0101001101001000

  • 我们可以容易的发现这就是令一个点沿着边走两步得到的边。

例题

XB的生日

  • 题目有三个限制条件
    • [1,T] 步回到原点。
    • 访问商店有额外的 cost
    • 买齐4个物品。
  • 我们来逐一解决他们

first

  • 我们需要算出 A1+A2+A3+A4+A5+A6An 中所有的 A[1][1] 和。我们可以通过构造矩阵来实现。
    [cnt1cnt2cntnans]001010000001>[cnt1cnt2cntnans]
  • cnti 表示从一出发可以达到的 i 的方案,我们再在原矩阵的边缘右边赋值成和A[i][1]一样,边缘右边下面为 0 ,把右下角赋值为1这样我们就做到了把 A1+A2+A3An 中所有的 A[1][1] 和记录到了 ans 中。
  • 解释一下:由于最后一列和 A[i][1] 是一样,故我们得到的点积即为
    ans=11+ans
  • 又由于矩阵满足结合律所以我们可以通过计算 BAn 得到答案。
  • 构造的思路,我们要求的是 A1+A2+A3An 中所有的 A[1][1] 于是,我们需要把所有的 A[1][1] 都加起来,我们分析可以得到
    A[1][1]=i=1ncntiA[i][1]
    ,我们要求的是 ans=A[1][1]+ans
    ans=i=1ncntiA[i][1]+ans
  • 其中 cnti A[i][1] 都是上一层的信息,这样就可以构造了。

then

  • 由于有些边的边权为2,所以我们可以把点裂开。如果你要去 i 买东西就先去i再到 i 即可。

last
  • 我们最后可以通过容斥原理限制买的集合得到答案。
  • 1111(1110+1011+0111+1101)+0011+1010+1100+10011000+0100+0010+0001+0000=ans
    (数字为1表示可以去用这样物品的店)。 ans 为一定买到所有物品的答案。
#include<bits/stdc++.h>
#define ID(a,b) ((a-1)*2+b)
using namespace std;
const int M=505,P=5557;
int a,n,m,T,ans,x[M],y[M],s[M];
char str[10];
struct Mat{
    int r,c,m[60][60];
    void init(int a,int b,bool f=0){
        r=a;c=b;
        for(int i=1;i<=r;i++)for(int j=1;j<=c;j++)m[i][j]=(bool)f&&(i==j);
    }void pt(){
        for(int i=1;i<=r;i++){for(int j=1;j<=c;j++)printf("%d",m[i][j]);puts("");}puts("");
    }
}A,B;
Mat operator*(const Mat &a,const Mat &b){
    Mat res;res.init(a.r,b.c);
    for(int k=1;k<=res.c;++k){
        for(int i=1;i<=res.r;++i){
            if(a.m[i][k]==0)continue;
            for(int j=1;j<=res.c;++j){
                if(b.m[k][j]==0)continue;
                res.m[i][j]=(a.m[i][k]*b.m[k][j]+res.m[i][j])%P;
            }
        }
    }return res;
}
Mat pow(Mat A,int n){
    Mat ans,p=A;
    ans.init(A.r,A.c,1);
    while(n){
        if(n&1)ans=ans*p,n--;
        n>>=1,p=p*p;
    }
    return ans;
}
int calc(int S){
    A.init(a,a);
    B.init(1,a);
    B.m[1][1]=1;
    A.m[a][a]=1;
    for(int i=1;i<=n;i++)A.m[ID(i,1)][ID(i,2)]=1;    
    for(int i=1;i<=m;i++){
        A.m[ID(x[i],1)][ID(y[i],1)]=1;  
        if((s[i]|S)==S)A.m[ID(x[i],2)][ID(y[i],1)]=1;
        if(y[i]==1){
            A.m[ID(x[i],1)][a]=1;
            if((s[i]|S)==S)A.m[ID(x[i],2)][a]=1;
        }
    }
    B=B*pow(A,T);
    return B.m[1][a];
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d %s",x+i,y+i,str);
        for(int j=0;j<strlen(str);j++){
            if(str[j]=='B')s[i]|=1;
            if(str[j]=='J')s[i]|=2;
            if(str[j]=='M')s[i]|=4;
            if(str[j]=='P')s[i]|=8;
        }
    }scanf("%d",&T);
    a=n*2+1;
    for(int i=0;i<16;i++){
        bool f=0;for(int j=0;j<4;j++)if(i&(1<<j))f^=1;
        ans=(ans+(f?-1:1)*calc(i))%P;
    }
    printf("%d",(ans%P+P)%P);
    return 0;
}

Gremlin的繁殖

  • 通过分析我们发现该题就是让我们求在图上通过一定的 cost 可以通过最多的边。
  • 又发现原图的边和点都已经固定了,于是我们可以利用矩阵来二分(倍增)。
include<bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
typedef long long ll;
void Min(ll &A,ll B){if(A>B)A=B;}
const int M=105;
const ll INF=1e15;
int n,A[M][1005];
ll T,ans;
struct Mat{
    ll m[M][M];
    Mat(){For(i,0,104)For(j,0,104)m[i][j]=INF;}
    bool operator <=(const ll &x)const{
        ll mi=INF;
        For(i,1,n)For(j,1,n)Min(mi,m[i][j]);
        return mi<=x;
    }
    Mat operator +(const Mat &A)const{
        Mat res;
        For(k,1,n)For(i,1,n)For(j,1,n)
            Min(res.m[i][j],m[i][k]+A.m[k][j]);
        return res;
    }
}S[55],O,t;
int main(){
    scanf("%d %lld",&n,&T);
    for(int i=1,x,c,l;i<=n;i++){
        scanf("%d %d",&l,&c);
        for(int j=1;j<=l;j++)scanf("%d",&A[i][j]);
        for(int j=1;j<=l;j++){
            scanf("%d",&x);
            Min(S[0].m[i][A[i][j]],1ll*x+c);
        }
    }
    for(int i=1;i<=50;i++)S[i]=S[i-1]+S[i-1];
    for(int i=1;i<=n;i++)O.m[i][i]=0;
    for(int i=50;i>=0;i--){
        Mat t=O+S[i];
        if(t<=T)ans+=1ll<<i,O=t;
    }
    printf("%lld\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
产品版本号:矩阵运算工具3.0 试用版 矩阵运算工具,是帷幄软件的核心产品,又称帷幄矩阵运算工具矩阵运算工具1.0和2.0为内部测试版本,矩阵运算工具3.0 现在推出试用版。 官方网站:http://www.veiwo.com; 官方论坛:http://www.veiwo.com/bbs。 矩阵运算工具是目前世界上,功能最强,体系结构最完善,操作最直观的关于矩阵运算工具。 该工具实现了矩阵所有的运算功能。包括双矩阵之间的加,减,乘,单矩阵的转置,行列式值,伴随矩阵矩阵求逆等多种运算。 该工具也是唯一实现了与Excel互联的关于矩阵运算工具,用户可以方便地从Excel导入与导出。处理速度非常快。 对于双矩阵运算,该工具的处理速度已达到了矩阵运算的极限。 为了方便用户,该工具的界面设置上,以及操作设置上,该工具完全与WINDOWS风格保持一直。完全做到了,只要会用WINDOWS,也就会用该工具。 本版本是帷幄软件推出的测试版本,目前仅提供一个月的试用,以后我们会不断改进,功能的增强值得大家期待。 有任何的疑问或需要帮助请到帷幄软件论坛提出(http://bbs.veiwo.com)。官方论坛有详细的操作说明。 帷幄软件:拥有全国最年轻的数学应用工具开发团队。 我们期待大家能够到官方论坛提出更好的发展和建议,共同努力让我们的软件做的更好。 我们的目标是:运筹帷幄,决胜千里 帷幄软件讨论QQ群:26079171 欢迎你的加入与其他同志共同探讨。 联系方式:zo.zo@163.com;veiwo@126.com 帷幄软件 2007年12月11日
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值