Capítulo 16: Matrizes II: Processamento e Cálculos Complexos (Somas, Diagonais e Rotas)

🎯 Objetivo da Aula

Uma matriz no computador não serve apenas para armazenar números: ela é o motor de consolidação contábil e roteirização operacional. Em auditorias fiscais, precisamos somar o total faturado por cada filial (somatório de linhas) ou descobrir qual trimestre foi mais produtivo na empresa (somatório de colunas).

Nesta aula, você aprenderá a:

  1. Implementar o algoritmo de Somatório por Linha (Totalização de Filial).
  2. Implementar o algoritmo de Somatório por Coluna (Totalização por Período).
  3. Processar e isolar a Diagonal Principal ($L = C$).
  4. Construir e consultar uma Matriz de Cotação de Rotas Cruzadas $4 \times 4$ (Origem $\times$ Destino).

📥 Material de Apoio e Código-Fonte da Aula:


🏢 O Cenário Prático (Seu Desafio)

Situação: O sistema tarifário da FastLog possui uma Matriz de Custos de Frete $4 \times 4$ interligando 4 capitais estratégicas:

  • 0: São Paulo (SP)
  • 1: Rio de Janeiro (RJ)
  • 2: Belo Horizonte (BH)
  • 3: Curitiba (PR)

A tarifa para transportar de uma cidade para ela mesma ([0][0], [1][1], etc.) é R$ 0,00 (Diagonal Principal). Para transportar de SP (0) para Curitiba (3), a tarifa é R$ 1.850,00 (rotas[0][3]).

Missão: Você deve programar a matriz de rotas, calcular a receita total por praça de origem e permitir a consulta instantânea de frete entre quaisquer duas capitais digitadas pelo operador.


🧠 Fundamentos: Algoritmos Avançados em Matrizes

graph TD
    A["Matriz de Rotas rotas[4][4]"] --> B["1. Somatório por Linha: Total de Saídas da Origem"]
    A --> C["2. Somatório por Coluna: Total de Chegadas no Destino"]
    A --> D["3. Diagonal Principal (l == c): Origem == Destino (Custo R$ 0,00)"]
    A --> E["4. Consulta Direta: rotas[origem][destino] -> O(1)"]
    
    style A fill:#8e44ad,stroke:#fff,color:#fff
    style B fill:#2980b9,stroke:#fff,color:#fff
    style C fill:#27ae60,stroke:#fff,color:#fff
    style D fill:#f39c12,stroke:#fff,color:#fff
    style E fill:#217346,stroke:#fff,color:#fff

1. Padrão de Somatório por Linha

Para somar cada linha individualmente, o acumulador somaLinha deve ser zerado antes de iniciar o laço interno c. O laço externo controla a linha (l); o laço interno percorre as colunas daquela linha:

1
2
3
4
5
6
7
8
9
para (inteiro l = 0; l < 4; l++) 
{
	real somaLinha = 0.0 // Zera a cada nova linha!
	para (inteiro c = 0; c < 4; c++) 
	{
		somaLinha += rotas[l][c]
	}
	escreva("Total da Linha [", l, "]: R$ ", somaLinha, "\n")
}

2. Padrão de Somatório por Coluna

Para somar por coluna em vez de por linha, basta inverter a ordem dos laços: o laço externo passa a controlar a coluna (c), e o laço interno percorre as linhas (l) daquela coluna. O acumulador é zerado a cada nova coluna:

1
2
3
4
5
6
7
8
9
para (inteiro c = 0; c < 4; c++) 
{
	real somaColuna = 0.0 // Zera a cada nova coluna!
	para (inteiro l = 0; l < 4; l++) 
	{
		somaColuna += rotas[l][c]
	}
	escreva("Total da Coluna [", c, "]: R$ ", somaColuna, "\n")
}

Repare que a única diferença estrutural para o Somatório por Linha é qual variável (l ou c) fica no laço de fora e qual é usada para zerar o acumulador — o corpo do laço interno (+= rotas[l][c]) é idêntico nos dois casos.


3. A Diagonal Principal ($L == C$)

A diagonal principal contém os elementos cujos índices de linha e coluna são idênticos ([0][0], [1][1], [2][2], [3][3]). Podemos percorrê-la com um único laço para:

1
2
3
4
para (inteiro i = 0; i < 4; i++) 
{
	escreva("Elemento Diagonal [", i, "][", i, "] = ", matriz[i][i], "\n")
}

4. Consulta Direta e Complexidade O(1)

Diferente de percorrer a matriz inteira com laços (que custa tempo proporcional ao número de elementos), acessar uma posição específica já conhecida — como rotas[origem][destino] — é instantâneo: o computador calcula o endereço de memória exato daquela posição diretamente, sem precisar comparar ou percorrer nenhum outro elemento. Por isso essa operação tem complexidade O(1) (“tempo constante”): o tempo de acesso não depende do tamanho da matriz.


📖 Exemplo Guiado: Matriz de Rotas e Tarifas $4 \times 4$

Código do Programa:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
programa 
{
	funcao inicio() 
	{
		// Cidades: 0-SP, 1-RJ, 2-BH, 3-PR
		cadeia capitais[4] = {"São Paulo (SP)", "Rio de Janeiro (RJ)", "Belo Horizonte (BH)", "Curitiba (PR)"}
		
		real rotas[4][4] = {
			{   0.0, 1200.0, 1400.0, 1850.0 }, // Saídas de SP
			{ 1200.0,    0.0, 1100.0, 2100.0 }, // Saídas de RJ
			{ 1400.0, 1100.0,    0.0, 2300.0 }, // Saídas de BH
			{ 1850.0, 2100.0, 2300.0,    0.0 }  // Saídas de PR
		}

		inteiro origem, destino

		escreva("==================================================\n")
		escreva("      FASTLOG - SIMULADOR DE ROTAS CRUZADAS       \n")
		escreva("==================================================\n")
		escreva(" CÓDIGOS DAS CIDADES:\n")
		escreva(" [0] São Paulo (SP)        [1] Rio de Janeiro (RJ)\n")
		escreva(" [2] Belo Horizonte (BH)   [3] Curitiba (PR)\n")
		escreva("--------------------------------------------------\n")

		escreva("Digite o código da Origem (0 a 3): ")
		leia(origem)
		escreva("Digite o código do Destino (0 a 3): ")
		leia(destino)

		escreva("\n")
		se (origem >= 0 e origem < 4 e destino >= 0 e destino < 4) 
		{
			escreva(">>> COTAÇÃO CONFIRMADA:\n")
			escreva("    Origem : ", capitais[origem], "\n")
			escreva("    Destino: ", capitais[destino], "\n")
			escreva("    Tarifa : R$ ", rotas[origem][destino], "\n")
		} 
		senao 
		{
			escreva(">> [ERRO]: Códigos de cidade inválidos!\n")
		}

		// Auditoria de Faturamento Potencial por Origem (Somatório de Linha)
		escreva("\n--- CAPACIDADE DE RECEITA MÁXIMA POR ORIGEM ---\n")
		para (inteiro l = 0; l < 4; l++) 
		{
			real somaOrigem = 0.0
			para (inteiro c = 0; c < 4; c++) 
			{
				somaOrigem += rotas[l][c]
			}
			escreva("Total Potencial de ", capitais[l], ": R$ ", somaOrigem, "\n")
		}
		escreva("==================================================\n")
	}
}

🛠️ Prática Obrigatória 1: Somatório de Faturamento por Trimestre (Soma de Colunas)

Passo 1: O Desafio

Dada a matriz de faturamento de 3 filiais por 4 trimestres: real faturamento[3][4] Crie um programa soma_colunas.por que inverta a ordem dos laços (para c de 0 ate 3 por fora e para l de 0 ate 2 por dentro) para calcular o faturamento total da empresa em cada trimestre (T1, T2, T3, T4).

✅ Resultado Esperado (Prática 1):

1
2
3
4
Total Faturado no Trimestre 1: R$ 450000.0
Total Faturado no Trimestre 2: R$ 520000.0
Total Faturado no Trimestre 3: R$ 610000.0
Total Faturado no Trimestre 4: R$ 890000.0

🛠️ Prática Obrigatória 2: Verificador de Rota Local (Diagonal Principal)

Crie um programa diagonal_rotas.por que leia a matriz de rotas $4 \times 4$ e comprove que todas as posições da Diagonal Principal (rotas[i][i]) possuem custo 0.0. Se alguma for maior que zero, exiba um alerta de inconsistência tarifária.


📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_16_SeuNome_SeuSobrenome.por.
  2. Certifique-se de que os acumuladores são zerados no local correto.
  3. No Microsoft Teams, envie na tarefa “Portugol Cap 16 - Cálculos em Matrizes”.
  4. Clique em Entregar (Turn In).

💡 Checkpoint de Lógica & Engenharia de Software

Você acabou de aplicar o conceito de Matrizes de Adjacência e Teoria dos Grafos. Algoritmos como o de Dijkstra (utilizado no Google Maps e no roteamento de pacotes TCP/IP na Internet) utilizam matrizes bidimensionais para encontrar a rota mais curta entre cidades.


🔥 Desafio de Fixação: Matriz Transposta

Crie um programa que leia uma matriz $2 \times 3$ e gere a sua Matriz Transposta $3 \times 2$ (onde as linhas viram colunas: transposta[c][l] = original[l][c]).


🔑 Gabarito de Código Completo

Prática 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
programa {
	funcao inicio() {
		real faturamento[3][4] = {
			{100000.0, 120000.0, 150000.0, 200000.0},
			{150000.0, 180000.0, 210000.0, 310000.0},
			{200000.0, 220000.0, 250000.0, 380000.0}
		}

		escreva("=== CONSOLIDAÇÃO POR TRIMESTRE (SOMA DE COLUNAS) ===\n")

		// Laço Externo de Colunas (Trimestres 0 a 3)
		para (inteiro c = 0; c < 4; c++) {
			real totalTrimestre = 0.0
			
			// Laço Interno de Linhas (Filiais 0 a 2)
			para (inteiro l = 0; l < 3; l++) {
				totalTrimestre += faturamento[l][c]
			}
			
			escreva("Total Faturado no Trimestre ", c+1, ": R$ ", totalTrimestre, "\n")
		}
	}
}

Prática 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
programa {
	funcao inicio() {
		real rotas[4][4] = {
			{ 0.0, 1200.0, 1400.0, 1850.0 },
			{ 1200.0, 0.0, 1100.0, 2100.0 },
			{ 1400.0, 1100.0, 0.0, 2300.0 },
			{ 1850.0, 2100.0, 2300.0, 0.0 }
		}

		logico matrizRegular = verdadeiro

		escreva("=== AUDITORIA DE DIAGONAL PRINCIPAL ===\n")
		para (inteiro i = 0; i < 4; i++) {
			se (rotas[i][i] != 0.0) {
				escreva("[INCONSISTÊNCIA] Custo não nulo na rota local [", i, "][", i, "]: R$ ", rotas[i][i], "\n")
				matrizRegular = falso
			}
		}

		se (matrizRegular) {
			escreva(">>> SUCESSO: Todas as rotas locais estão zeradas (Diagonal Principal 100% OK).\n")
		}
	}
}

Desafio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
programa {
	funcao inicio() {
		inteiro original[2][3] = {
			{1, 2, 3},
			{4, 5, 6}
		}
		inteiro transposta[3][2]

		// Transposição
		para (inteiro l = 0; l < 2; l++) {
			para (inteiro c = 0; c < 3; c++) {
				transposta[c][l] = original[l][c]
			}
		}

		escreva("=== MATRIZ TRANSPOSTA 3x2 ===\n")
		para (inteiro l = 0; l < 3; l++) {
			para (inteiro c = 0; c < 2; c++) {
				escreva(transposta[l][c], "  ")
			}
			escreva("\n")
		}
	}
}

📝 Atividade Extra: Questionário de Fixação (Caderno)

Instruções: Responda no caderno, de próprio punho, as 10 perguntas abaixo com base no que foi estudado neste capítulo. Ao concluir, leve o caderno até o professor para correção e visto.

  1. No padrão de Somatório por Linha apresentado nos Fundamentos, por que o acumulador somaLinha deve ser zerado a cada nova linha, antes de iniciar o laço interno c?
  2. O que caracteriza os elementos da Diagonal Principal de uma matriz, e com quantos laços para é possível percorrê-la?
  3. No Cenário Prático, qual é a tarifa de frete entre uma cidade e ela mesma na Matriz de Custos de Frete, e em que posições da matriz essa tarifa se localiza?
  4. No Exemplo Guiado, qual é a tarifa (em R$) para transportar de São Paulo (código 0) para Curitiba (código 3), segundo a matriz rotas?
  5. Na Prática Obrigatória 1 (Somatório de Faturamento por Trimestre), como deve ser invertida a ordem dos laços para calcular o total por coluna (trimestre) em vez do total por linha (filial)?
  6. Na Prática Obrigatória 2 (Verificador de Rota Local), o que o programa deve verificar sobre a Diagonal Principal da matriz de rotas, e o que deve fazer se encontrar uma inconsistência?
  7. Segundo o Checkpoint de Lógica & Engenharia de Software, a que conceito da Teoria dos Grafos as matrizes bidimensionais são associadas, e qual algoritmo famoso é citado como exemplo de uso?
  8. No Exemplo Guiado, o que o programa faz quando o código de origem ou de destino digitado pelo operador está fora do intervalo de 0 a 3?
  9. Segundo os Fundamentos, qual é a complexidade de uma consulta direta a uma rota específica, como rotas[origem][destino]?
  10. Dê um exemplo do dia a dia em que uma tabela de custos ou distâncias entre pontos (como a matriz de rotas da FastLog) poderia ser útil fora do contexto de programação.