行索引稀疏矩阵查找某一列的元素没那么方便,所以在做矩阵乘法时(这里以M乘N=Q为例),严书的做法是:在求Q的某一行的值是,用M的一行去遍历N的每一行,对结果中同列的值进行累加,最后稀疏化存入Q的当前行中,这个过程还原成正常矩阵比较容易理解:
求Q(2,2)的第一行时,肯定是M的第一行和N的第一列逐乘再累加,然后再M的第一行和N的第二列逐乘累加
M(2,3)* N(3,2):
直接算的话就是:
Q[1,1] = 1*1 + 2*0 + 3*1 = 1+0+3 = 4
Q[1,2] = 1*0 + 2*1 + 3*1 = 0+2+3 = 5
这回我们直接同时求两列的值,其实就是改变一下计算顺序:
这个就相当于严书代码中ctemp的作用,只不过ctemp是直接累加.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_E = 1e+4+5, MAX_R = 105;
//严版特色,下标从1开始
struct Triple{
int i,j,e;};
struct RLSMatrix{
Triple data[MAX_E];
int rpos[MAX_R];//行首索引, rpos[i]指向第i行中的首元素在data中的序号, 则rpos[i+1]-1指向第i行中最后一个非0元素在N.data中的序号.
int rows, cols, elems;
};
int ctemp[MAX_R];//Q的第i行元素结果累加器,算完一行就压缩存储进Q.data中
RLSMatrix mul(RLSMatrix M, RLSMatrix N){
RLSMatrix Q;
Q.rows = M.rows;Q.cols = N.cols;Q.elems = 0;
if(M.elems * N.elems != 0){
// Q是非零矩阵
for(int arow = 1; arow <= M.rows; arow++){
memset(ctemp, 0, sizeof(ctemp)); //到了下一行,清零
Q.rpos[arow] = Q.elems+1; //新一行的行首索引是当前data中元素个数+1,从该处继续向data中存三元组
int tp; //用tp指向data中该行行末的下一个位置,方便遍历
if(arow < M.rows) tp = M.rpos[arow+1]; //如果不是最后一行, tp指向下一行行首
else tp = M.elems+1; //最后一行, tp直接指向data中最后一个+1
for(int p = M.rpos[arow];p < tp; p++){
//对当前行找到的每一个非零元
int brow = M.data[p].j; //找到对应元在N中的行号(M中某行第三列的元素, 肯定和N中第三行某列的元素相乘)
int t;//和tp同样的套路
if(brow < N.rows) t = N.rpos[brow+1];
else t = N.elems+1;
for(int q = N.rpos[brow]; q < t; q++){
//这里不是直接算出M的某行乘N的某列的值
//而是用M的某行,去遍历N的所有行,然后对每行的应该在同列的值进行累加
int ccol = N.data[q].j;
ctemp[ccol] += M.data[p].e * N.data[q].e;//累加器
}
}//求得Q中第crow(=arow)行的非零元
for(int ccol = 1; ccol <= Q.cols; ++ccol){
//用M的一行遍历完了整个N矩阵
if(ctemp[ccol]){
Q.data[++Q.elems] = {
arow, ccol, ctemp[ccol]};//压缩存储
}
}
}
}
return Q;
}
RLSMatrix makeMat(){
/*
* 输入rows, cols, 三元组个数
* 输入三元组
*/
RLSMatrix A;
cin>>A.rows>>A.cols>>A.elems;
for(int i = 1;i <= A.elems;i++){
int x,y,e;
cin>>x>>y>>e;
A.data[i] = {
x,y,e};
}
/*
根据乘法中这段代码写的初始化rpos数组:
int tp; //用tp指向data中该行行末的下一个位置,方便遍历
if(arow < M.rows) tp = M.rpos[arow+1]; //如果不是最后一行, tp指向下一行行首
else tp = M.elems+1; //最后一行, tp直接指向data中最后一个+1
for(int p = M.rpos[arow];p < tp; p++) ...
可以看出如果某行没有元素,则让tp = M.rpos[arow]则可不进行遍历,也就是M.rpos[arow] = M.rpos[arow+1]
而当最后几行为空时,并不会执行else tp = M.elems+1;这时应该把rpos最后几行空的填成M.elems+1
*/
int row = 1;
for(int e = 1;e <= A.elems; e++){
int arow = A.data[e].i;
while(row <= arow){
A.rpos[row++] = e;
}
}
while(row <= A.rows){
//如果最后几行没有元素,让索引指到elems+1的位置
A.rpos[row++] = A.elems+1;
}
return A;
}
void printMat(RLSMatrix A){
cout<<"rows:"<<A.rows<<" cols:"<<A.cols<<" elems:"<<A.elems<<endl;
cout<<"-------------------------"<<endl;
cout<<"data:"<<endl;
for(int i = 1;i <= A.elems;i++) {
cout<<setw(4)<<A.data[i].i<<setw(4)<<A.data[i].j<<setw(4)<<A.data[i].e<<endl;
}
cout<<"-------------------------"<<endl;
cout<<"rpos: ";
for(int j = 1;j <= A.rows; j++){
cout<<A.rpos[j]<<' ';
}
cout<<endl<<endl;
}
int main(){
ios::sync_with_stdio(false);
RLSMatrix A = makeMat();
printMat(A);
RLSMatrix B = makeMat();
printMat(B);
RLSMatrix C = mul(A, B);
printMat(C);
return 0;
}
/*
严书上的例子
3 4 4
1 1 3
1 4 5
2 2 -1
3 1 2
4 2 4
1 2 2
2 1 1
3 1 -2
3 2 4
*/
文章浏览阅读1.5k次。1,MyUtuils.kt将被调用的文件class MyUtils { fun show(info:String){ println(info) }}fun show(info:String){ println(info)}2,Java文件调用该类,ClientJava.javapublic class ClientJava { public static void main(String[] args) { /** _java 调用kt 对象
文章浏览阅读6.6k次,点赞4次,收藏4次。在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好? 当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对 像ICQ一类的发送聊天消息的情况作分析,对于其他情况,你或许也能得到一点帮助: 首先,我们知道,TCP/IP通常被认为是一个四层协议系统,包括链路层,网络层,运输层,应用层. UDP属于运输层_最大请求报文大小
文章浏览阅读10w+次,点赞14次,收藏18次。代码如下:for /l %a in (0,0,1) do echo hello,world粘贴在cmd命令行窗口中,回车即可无限死循环输出hello,world。如果需要停止,可以按ctrl+c中断。解析通用形式:for /l %variable IN (start,step,end) DO command [command-parameters] 该集表示以增量形式从start到end的一个数字序列。具体到第一段代码,如果是 (0,0,1) 就是从0开始,每次增_cmd装比代码无限循环
文章浏览阅读917次,点赞18次,收藏11次。为了方便有学习需要的朋友,我把资料都整理成了视频教程(实际上比预期多花了不少精力)当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。
文章浏览阅读2k次,点赞5次,收藏14次。1、写出微分方程函数2、求解function dy=rigid(t,y)dy=zeros(3,1);dy(1)=y(2)*y(3);dy(2)=-y(1)*y(3);dy(3)=-0.51*y(1)*y(2);end%将微分方程写成函数形式,待调用options=odeset('RelTol',1e-4,'AbsTol',[1e-4 1e-4 1e-5]);[T Y]=ode45(@rigid,[0 12],[0 1 1],options);plot(T,Y(:,1),'-',T,Y_ode函数离散
文章浏览阅读3.8w次,点赞41次,收藏180次。==操作符与equals方法的区别_java中==和equals的区别
文章浏览阅读218次。1.官方的建议1.1 电池续航时间优化(Optimizing Battery Life)参考文章:优化电池使用时间已有中文的详细说明,此处做简要说明:(1)监控电池电量和充电状态(Monitoring the Battery Level and Charging State)通过系统广播,获取充电状态和电池电量的变化来调整数据更新等操作;如在充电时,更新数据及应用,在低电量时,减少更新频..._com.tencent.mm:exdevice
文章浏览阅读818次,点赞14次,收藏9次。计算e1=2.718,e5=148.413,e3=20.086,e1+e5+e3=171.217。“人/B 们/E 常/S 说/S 生/B 活/E 是/S 一/S 部/S 教/B 科/M 书/E ”给一段文字做分词标注,标注每个字对应的标号。图中是双向的三层 RNNs,堆叠多层的RNN网络,可以增加模型的参数,提高模型的拟合。双向的 RNN 是同时考虑“过去”和“未来”的信息,输入(黑色点)沿着黑色的实线箭。比如标签0将表示为([1,0,0,0,0,0,0,0,0,0]),标签3将表示为。
文章浏览阅读513次,点赞9次,收藏10次。无法加载DLL"halconxl": 找不到指定的模块。(异常来自HRESULT:0X8007007E)。在exe安装目录中中添加halconxl.dll文件继续运行就了。_c#如何免安装halcon12
文章浏览阅读1k次,点赞11次,收藏9次。你的键盘上应该有两个Ctrl键,按右边的Ctrl解决了。_键盘一直自动按ctrl
文章浏览阅读141次。Linux 命令【6】:cut文章目录一、简介二、命令详解三、实例演示一、简介cut 命令是一个将文本按列进行切分的小工具,它可以指定分隔每列的定界符。二、命令详解命令格式:cut {选项} {文件名}选项:-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。-c :以字符为单位进行分割。-d :自定义分隔符,默认为制表符。-f :与-d一起使用,指定显示哪个区域。-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一._cut使用特殊字符为分隔符
文章浏览阅读2.4k次。/** * 播放audio标签视频控制 * */ //等待音频加载完毕 点击每一段录音进行播放 $('.lis').click(function(){ $('.j_voiceCont').show(); var src = $(this).attr("src"); $(this).addClass('c_audiotrack可以设置进度吗