算法证明:记输入图像中{像素起点,起点的相邻点,左下角点}为集合A,输出图像中像素起点为集合B,那么B是A的子集。
证明:
假设存在点x属于集合B,但是不属于集合A,即输出中的起始点不属于输入中的{起始点、与起始点相邻的点、左下角点}
对于输入图像:
1)若x是左上角点
因为是第一个点,无论输入图还是输出图,都是线段的起始点。
即该点属于A,也属于B。
故假设不成立。
2)若x是右上角点
. . a x
. . b c
. . . .
因为a、b、c都不是起始点,
故上图可以转化为:
. a a x
. b b b
. . . .
此时x本身为起点,当然既属于A,又属于B。
故假设不成立。
3)若x是左下角点
假设直接不成立!
因为此点作为特殊点已加入A,故该点不管是否在B中出现,一定在A中。但,为什么要把它作为特殊点呢?
. .
a b .
x c .
此时左下角的点虽然不是起始点,也不与任一个起始点相邻,但是此处的输出值为|a-x|,
但是倒数第二行最右侧的x,输出值为max{|x-e|、|x-d|、|x-f|、|x-g|、|x-h|},
故,该点必须要考虑。
. . d e
a a . f x
x x . g h
4)若x是右下角点
. a a a
. d d x
此处x本身为起始点也!,属于A,同2)所述。
故,假设不成立。
5)若x是非边界点
. . . . .
. a b c .
. d x e .
. f g h .
. . . . .
因为a、b、c、d、e、f、g、h都不是起始点
那么,a=b=c d=x=e f=g=h
故上图可入下转化:
. . . . .
a a a a .
x x x x .
f f f f .
. . . . .
注意:最左侧一列可能是边界,也可能不是。
此时,第三列的x与第二列的x在输出中对应的值相同,因此不可能是输出线段的起点。
此时x虽然不属于A,但同时不可能属于B。
故假设不成立。
证明:
假设存在点x属于集合B,但是不属于集合A,即输出中的起始点不属于输入中的{起始点、与起始点相邻的点、左下角点}
对于输入图像:
1)若x是左上角点
因为是第一个点,无论输入图还是输出图,都是线段的起始点。
即该点属于A,也属于B。
故假设不成立。
2)若x是右上角点
. . a x
. . b c
. . . .
因为a、b、c都不是起始点,
故上图可以转化为:
. a a x
. b b b
. . . .
此时x本身为起点,当然既属于A,又属于B。
故假设不成立。
3)若x是左下角点
假设直接不成立!
因为此点作为特殊点已加入A,故该点不管是否在B中出现,一定在A中。但,为什么要把它作为特殊点呢?
. .
a b .
x c .
此时左下角的点虽然不是起始点,也不与任一个起始点相邻,但是此处的输出值为|a-x|,
但是倒数第二行最右侧的x,输出值为max{|x-e|、|x-d|、|x-f|、|x-g|、|x-h|},
故,该点必须要考虑。
. . d e
a a . f x
x x . g h
4)若x是右下角点
. a a a
. d d x
此处x本身为起始点也!,属于A,同2)所述。
故,假设不成立。
5)若x是非边界点
. . . . .
. a b c .
. d x e .
. f g h .
. . . . .
因为a、b、c、d、e、f、g、h都不是起始点
那么,a=b=c d=x=e f=g=h
故上图可入下转化:
. . . . .
a a a a .
x x x x .
f f f f .
. . . . .
注意:最左侧一列可能是边界,也可能不是。
此时,第三列的x与第二列的x在输出中对应的值相同,因此不可能是输出线段的起点。
此时x虽然不属于A,但同时不可能属于B。
故假设不成立。
综上所述,不存在一个点x属于B但是不属于A。反之,若一个点属于B,那么一定属于A。
/*
题意:图像使用RLE编码(详细内容请自查)方式进行存储。现有边缘检测算法,输出的像素值为输入像素值与周围像素值差值的最大绝对值。
请使用RLE编码输出经过边缘检测算法处理后的图像。
算法:记输入图像中{像素起点,起点的相邻点,左下角点}为集合A,输出图像中像素起点为集合B,那么B是A的子集。
因此,可将暴力枚举法(枚举输入的每个像素点)转化为枚举集合A中的点。
1.找出所有输入像素的起点及其周围的点+左下角点,记为集合A
2.枚举集合A中的每个点a,求其与周围像素点差值的最大绝对值,其结果记为集合B
3.将集合B的结果整理后输出
难度:****
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
int pairs[1010][3]; // pairs[i][0]=m:第i组输入的像素值为m pairs[i][1]=n:第i组输入像素的个数为n pairs[i][2]=p:第0-i组输入的共有n个像素
int possible[10000]; // possible[i]=j:集合A中第i个元素,其位置为j
int ans[10000]; // ans[i]=j:集合B中的第i个元素,其值j对应输出图像的值
int indexes[9][3] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1 }, {0, 0}, {0, 1}, {1, -1 }, {1, 0}, {1, 1}}; // 共9个方向,(0,0)为原地不动
int comp(const void*a,const void*b)
{
return *(int*)a-*(int*)b;
}
// 输入像素位置key,返回其对应的像素值
int binarySearch(int key,int pairs_num)
{
int low = 0;
int high = pairs_num - 1;
int mid;
while (low < high)
{
mid = (low+high) / 2;
(pairs[mid][2] <= key)? low = mid + 1 : high = mid;
}
return pairs[low][0];
}
// 输入像素位置idx,返回与周围点差值的最大绝对值
int getMaxValue(int idx,int sum_pixels,int pairs_num,int width,int height)
{
int max = -1;
int center = binarySearch(idx,pairs_num);
int row = idx / width;
int column = idx % width;
// 枚举像素idx周围的九个像素点loc,计算差值
for (int i=0; i<9; i++)
{
int r = row + indexes[i][0];
int c = column + indexes[i][1];
if (r < 0 || r >= height || c < 0 || c >= width)
{
continue;
}
int loc = r * width + c;
int around = binarySearch(loc,pairs_num); // 像素loc对应的像素值
int diff = abs(center-around);
if (diff >= max)
{
max = diff;
}
}
return max;
}
int main()
{
int width,height; // the width and height of the image
while (true)
{
scanf("%d",&width);
if (width == 0)
{
break;
}
// init arrays
memset(pairs,0,sizeof(pairs));
memset(possible,0,sizeof(possible));
memset(ans,-1,sizeof(ans));
int pairs_num = 0; // the number of the input pairs
int pixels_num = 0; // the number of the total pixels
/*
pairs 0 1 2
0 15 4 4
1 100 15 19
2 25 2 21
... ... .. ..
*/
while (true)
{
scanf("%d%d",&pairs[pairs_num][0],&pairs[pairs_num][1]); // pairs[i][0]:pixel value pairs[i][1]:the number of the same pixel
if (pairs[pairs_num][0] == 0 && pairs[pairs_num][1] == 0)
{
break;
}
pixels_num += pairs[pairs_num][1];
if (pairs_num == 0)
{
pairs[pairs_num][2] = pairs[pairs_num][1];
}
else
{
pairs[pairs_num][2] = pairs[pairs_num-1][2] + pairs[pairs_num][1]; // pairs[i][2]:the sum of the pixels from pair 0 to pair i
}
pairs_num++;
}
// the height of the image
height = pixels_num / width;
// 根据输入图像的线段起点计算其周围9个点(包含自身)的像素位置,
int t = 0;
int possible_num=0;
for (int i=0; i<pairs_num; i++)
{
int possible_pixel;
for (int j=0; j<9; j++)
{
// 第i个起点的坐标(row,column)
/*
等价与 row = pairs[i-1][2] / width;
column = pairs[i-1][2] %width;
因为: pairs[i-1][2] + pairs[i][1] = pairs[i][2]
但是如果使用 pairs[i-1][2],还需要考虑i=0的情况
*/
int row = (pairs[i][2] - pairs[i][1]) / width; // 等价于pairs[i-1][2]/width
int column = (pairs[i][2] - pairs[i][1]) % width;
// 计算周围的9个点
int r = row + indexes[j][0];
int c = column + indexes[j][1];
// 超出边界
if (r < 0 || r >= height || c < 0 || c >= width)
{
continue;
}
// possible_pixel:输入图像中的像素点位置,该位置对应的像素可能是输出图像中某像素的起点
possible_pixel = r * width + c;
// 检查该像素是否已经存储在possible数据中
int k=0;
for (k=0; k<possible_num; k++)
{
if (possible[k] == possible_pixel)
{
break;
}
}
// possible[i]=j:第i个输出图像中可能的起点在输入图像中的位置是j
if (k >= possible_num)
{
possible[possible_num++] = possible_pixel;
}
}
}
// 左下角的点
possible[possible_num++] = width*(height-1); // 至此,集合A求毕。
// 对数组possible进行排序,排序后再处理可保证输出像素的有序性
qsort(possible,possible_num,sizeof(int),comp);
// ans[i]=j:第i个像素与周围点差值的绝对值最大是j
for (int i=0; i<possible_num; i++)
{
ans[i] = getMaxValue(possible[i],pixels_num,pairs_num,width,height);
}
// 输出结果
possible[possible_num] = pixels_num; // 此设置方便最后线段的输出
printf("%d\n",width);
for (int i=0; i<possible_num; )
{
int start = i;
while (ans[start] == ans[i])
{
i++;
}
printf("%d %d\n",ans[start],possible[i]-possible[start]);
}
printf("0 0\n");
}
// 此处输出很重要!
printf("0\n");
}