第四天补题

本文探讨了矩阵处理中的几个关键问题,包括如何避免字符读取时的空格和换行干扰、如何高效地进行矩阵初始化,以及如何通过前缀和的方法解决0-1矩阵中的桥建造问题。还提供了一个支持大整数运算的int128类型介绍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

签到题:卡字符的读取

给定一个字符矩阵,判断是否对角线上字符全部相同,对角线外字符全部相同,且它们不同

这里主要考察字符矩阵的读取

如果直接用scanf("%c")会读入空格和换行

换成整数:

cin>>c 会导致cin错误 scanf(“%d”)也会导致scanf错误(不能直接从字符读入转换成整数,只有printf的时候可以有多种转换方式)

最后的解决:

while(cin>>a){
if(a==' '||a=='\n')
continue;
else break;
	}
matrix[i][j]=a;


memset逐字节赋值的效率

和总体直接初始化的效率相比,经过前人测试:

测试结果表明:memset比普通的初始化快7倍,所以应该多用memset来完成初始化工作。但,最根本还是应该减少计算机的计算量。


2.C题目

C题:给定一个0,1矩阵,相邻如果都是1则可以建造一座桥

然后问一个方块矩阵内可以建造多少座桥。(查询次数比较多)

<span style="font-size:18px;">bfs 超时。。</span>
<span style="font-size:18px;">#include <iostream>
#include <queue>
using namespace std;
const int maxn=520;
int N,M,Q;
bool connect[maxn][maxn];
int x1,y1,x2,y2;
bool isvisited[maxn][maxn];
typedef pair<int,int> Point;
int cnt;
void bfs(){
	queue<Point> Q;
	int NumOfChecked=0;
	while(NumOfChecked<(x2-x1+1)*(y2-y1+1)){
		bool out_flag=false;
		for(int i=x1;i<=x2;i++){
			for(int j=y1;j<=y2;j++){
				if(isvisited[i][j]) continue;
				isvisited[i][j]=true;
				NumOfChecked++;
				if(connect[i][j])
				{
					Q.push(make_pair(i,j));
					out_flag=true;
					break;
				}
			}
			if(out_flag) break;
		}
		while(!Q.empty()){
		Point out=Q.front(); Q.pop();
		//cout<<"x1=="<<out.first<<"y1=="<<out.second<<endl;
		if(out.first+1<=x2){
			if(!isvisited[out.first+1][out.second]){
				NumOfChecked++;
				isvisited[out.first+1][out.second]=true;
				if(connect[out.first+1][out.second]){
				Q.push(make_pair(out.first+1,out.second));
				cnt++;
				}
			}
			else{
				if(connect[out.first+1][out.second]){
				cnt++;
				}
			}
		}
		if(out.second+1<=y2){
			if(!isvisited[out.first][out.second+1]){
				NumOfChecked++;
				isvisited[out.first][out.second+1]=true;
				if(connect[out.first][out.second+1]){
				Q.push(make_pair(out.first,out.second+1));
				cnt++;
				}
			}
			else{
				if(connect[out.first][out.second+1]){
				cnt++;
				}
			}
		}
	}
}
}
int main(int argc, char const *argv[])
{
	int cases;
	cin>>cases;
	while(cases--){
		cin>>N>>M;
		for(int i=1;i<=N;i++){
			for(int j=1;j<=M;j++){
				cin>>connect[i][j];
			}
		}
		// for(int i=1;i<=N;i++){
		// 	for(int j=1;j<=M;j++){
		// 		cout<<connect[i][j]<<" ";
		// 	}
		// 	cout<<endl;
		// }
		cin>>Q;
		for(int k=1;k<=Q;k++){
			cnt=0;
			cin>>x1>>y1>>x2>>y2;
			for(int i=x1;i<=x2;i++){
				for(int j=y1;j<=y2;j++){
					isvisited[i][j]=false;
				}
			}
			bfs();
			//cout<<"here"<<endl;
			cout<<cnt<<endl;
		}
	}
	return 0;
}</span>



zcy学长说了一种前缀和的方式:

班长认为可以只考虑向右和向下的连通性(显然这样可以做到不重复计算一座桥),对于每个点,F[i][j]为向右向下联通数量

sum[i][j]为1,1到i,j的F[i][j]的和

那么为了计算x1,y1,x2,y2区间内的连通数,需要做的是sum[x2][y2]-sum[x1-1][y2]-sum[x2][y2-1]+sum[x1-1][y1-1](左上部分减了两次)

当然,还有x2行和y2列向右向下的连通性,这个只需要O(N)扫描一遍就可以了。

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=520;
int N,M,Q;
bool connect[maxn][maxn];
int x1,y1,x2,y2;
bool R[maxn][maxn];
bool D[maxn][maxn];
int sum[maxn][maxn];
int cnt;

int main(int argc, char const *argv[])
{
	int cases;
	cin>>cases;
	while(cases--){
		cin>>N>>M;
		for(int i=1;i<=N;i++){
			for(int j=1;j<=M;j++){
				cin>>connect[i][j];
				R[i][j]=D[i][j]=false;
			}
		}
		for(int i=1;i<=N;i++){
			for(int j=1;j<=M;j++){
				if(i+1<=N&&connect[i][j]&&connect[i+1][j])
					D[i][j]=true;
				if(j+1<=M&&connect[i][j]&&connect[i][j+1])
					R[i][j]=true;
			}
		}
		for(int i=1;i<=N;i++){
			for(int j=1;j<=M;j++){
				sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+R[i][j]+D[i][j];
			//	printf("sum[%d][%d]=%d  ",i,j,sum[i][j] );
			}//正确性显然,比如我们要获得[1][1]到[i][j]内的连通数
			//我们只要获得到[i-1][j]的连通数,[i][j]这一点的连通性
			//再考虑i这一行的连通数即可,但是这一行的连通数就是sum[i][j-1]-sum[i-1][j-1]
			//printf("\n");
		}
		cin>>Q;
		for(int k=1;k<=Q;k++){
			cin>>x1>>y1>>x2>>y2;
			cnt=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
			//cout<<"original"<<cnt<<endl;
			for(int i=x1;i<=x2;i++){
				cnt-=R[i][y2];
			}
			for(int i=y1;i<=y2;i++){
				cnt-=D[x2][i];
			}
			cout<<cnt<<endl;
		}
	}
	return 0;
}



3._int128的使用 ??

大约能够支持10^40级别的运算

As an extension the integer scalar type __int128 is supported for targets which have an integer mode wide enough to hold 128 bits. Simply write __int128 for a signed 128-bit integer, or unsigned __int128 for an unsigned 128-bit integer. There is no support in GCC for expressing an integer constant of type __int128 for targets with long long integer less than 128 bits wide.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值