HiHoCoder [Offer收割]编程练习赛6 C. 图像算子(高斯消元小数版)

传送门

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

在图像处理的技术中,经常会用到算子与图像进行卷积运算,从而达到平滑图像或是查找边界的效

果。

假设原图为 H×W 的矩阵 A ,算子矩阵为 D×D 的矩阵 Op ,则处理后的矩阵 B 大小为

(HD+1)×(WD+1)。其中:

B[i][j]=(A[i1+dx][j1+dy]Op[dx][dy])|(dx=1..D,dy=1..D),1iHD+1,1jWD+1

给定矩阵 A B ,以及算子矩阵的边长 D 。你能求出算子矩阵中每个元素的值吗?

输入

1 行: 3 个整数,H,W,D分别表示原图的高度和宽度,以及算子矩阵的大小。

5H,W601D5D 一定是奇数。

2..H+1 行:每行 W 个整数,第 i+1 行第 j 列表示A[i][j]0A[i][j]255

接下来 HD+1 行:每行 WD+1 个整数,表示 B[i][j]B[i][j] int 范围内,可能

为负数。

输入保证有唯一解,并且解矩阵的每个元素都是整数。

输出

1..D 行:每行 D 个整数,第 i 行第 j 列表示 Op[i][j]

样例输入


5 5 3
1 6 13 10 3
13 1 5 6 15
8 2 15 0 12
19 19 17 18 18
9 18 19 5 17
22 15 6
35 -36 51
-20 3 -32

样例输出

0 1 0
1 -4 1
0 1 0

解题思路:

其实将这个题目转化一下的话 就是一个高斯消元的问题,首先我们按照题目意思列出

WD+1HD+1 个方程,包含 DD 个未知数的方程,然后通过高斯消元

模板,就可以搞定了。

具体的说一下怎么构造的这些方程组,就拿样例来说吧:

A:   113819961219181351517191060185315121817

因为 D 矩阵的长度是 3 ,所以 B 矩阵的的规模是 (53+1) (53+1) 的,嗯哼,那么

就是相当于 A 矩阵的每个子矩阵中的数分别乘以 D 矩阵的数,这个其实说不太明白 最好是在纸上

画一画基本上就出来了,分别对应相乘完之后,得到 (HD+1)(WD+1) 个方程和

DD 个未知数,在这里需要注意的是,构造的增广矩阵是 double 的,解也是 double 的。具体还是 看我的代码吧。

My Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;

typedef long long LL;
const double eps = 1e-7;
const int MAXN = 1e4+5;
int equ, var;///equ个方程 var个变量
double a[MAXN][100];///增广矩阵
double x[MAXN];///解的数目
void Gauss()
{
    int Max_r;///当前列绝对值最大的存在的行
    ///col:处理当前的列
    int row = 0;
    int free_x_num;
    int free_index;
    for(int col=0; row<equ&&col<var; row++,col++)
    {
        Max_r = row;
        for(int i=row+1; i<equ; i++)
            if(fabs(a[i][col]) > fabs(a[Max_r][col]))
                Max_r = i;

        if(Max_r != row)
            for(int i=0; i<var+1; i++)
                swap(a[row][i], a[Max_r][i]);
        for(int i=row+1; i<equ; i++)
        {
            double f = a[i][row]/a[row][col];
            for(int j=col; j<var+1; j++)
                a[i][j] -= f*a[row][j];
        }
    }
    for(int i=equ-1; i>=0; i--)
    {
        double tmp = a[i][var];
        for(int j=i+1; j<var; j++)
            tmp -= a[i][j]*x[j];
        x[i] = tmp/a[i][i];
    }
}
double aa[70][70];
int main()
{
    int H, W, D;
    while(~scanf("%d%d%d",&H,&W,&D))
    {
        for(int i=0; i<H; i++)
            for(int j=0; j<W; j++)
                scanf("%lf",&aa[i][j]);
        memset(a, 0, sizeof(a));
        memset(x, 0, sizeof(x));
        equ = (H-D+1)*(W-D+1);
        var = D*D;
        for(int i=0; i<equ; i++)
            scanf("%lf",&a[i][var]);
        for(int i=0; i<equ; i++)
            for(int j=0; j<var; j++)
                a[i][j] = aa[i/(W-D+1)+j/D][i%(W-D+1)+j%D];
        Gauss();
        for(int i=0; i<D*D; i++)
        {
            int k = floor(x[i]+0.5);
            if(i%D == D-1)
                printf("%d\n",k);
            else
                printf("%d ",k);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值