#pragma warning(disable : 4996)
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define maxSize 200
#define byte unsigned char
int GetColorForResult(int row, int col);
int GetColorForDiffValue(int row, int col);
bool badPoints[maxSize][maxSize];
void ClearBadPoints()
{
for (int i=0; i<maxSize; i++)
for (int j=0; j<maxSize; j++)
{
badPoints[i][j] = false;
}
}
byte sourceImage[maxSize][maxSize];
byte resultImage[maxSize][maxSize];
int q, h, w;
void ReadImage()
{
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
scanf("%d", &sourceImage
[i
][j
]);
}
}
}
void WriteImage()
{
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
printf("%d", resultImage
[i
][j
]);
}
}
}
long diffcount;
struct Diff
{
int i, j, value;
};
Diff diffs[maxSize*maxSize];
void CopySourceToResult()
{
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
resultImage[i][j] = sourceImage[i][j];
}
}
}
void CopyResultToSource()
{
for (int i=0; i<h; i++)
{
for (int j=0; j<w; j++)
{
sourceImage[i][j] = resultImage[i][j];
}
}
}
void QuickSort(long k1, long k2)
{
long in1, in2;
int Temp;
Diff v;
if ((k2-k1)
> 1)
{
in1 = k1;
in2 = k2;
Temp = diffs[(k1+k2) / 2].value;
do
{
while (diffs[in1].value > Temp) in1++;
while (diffs[in2].value < Temp) in2--;
if (in1 <= in2)
{
v = diffs[in1];
diffs[in1] = diffs[in2];
diffs[in2] = v;
in1++;
in2--;
}
} while (in1 <= in2);
if (k1 < in2) QuickSort(k1, in2);
if (in1 < k2) QuickSort(in1, k2);
}
else
{
if (diffs[k1].value < diffs[k2].value)
{
v = diffs[k1];
diffs[k1] = diffs[k2];
diffs[k2] = v;
}
}
}
void SortDiffs()
{
QuickSort(0, diffcount-1);
}
void ApplyDiffs()
{
long actualCount = h * w * q / 100;
if ((diffcount > 0) && (actualCount > 0))
{
for (int i=0; i<diffcount; i++)
{
diffs
[i
].
value =
abs(GetColorForDiffValue
(diffs
[i
].
i, diffs
[i
].
j) - sourceImage
[diffs
[i
].
i][diffs
[i
].
j]);
}
SortDiffs();
if (diffcount < actualCount)
{
actualCount = diffcount;
}
for (int i=0; i<actualCount; i++)
{
resultImage[diffs[i].i][diffs[i].j] = GetColorForResult(diffs[i].i, diffs[i].j);
}
}
}
int GetCountBigger(int row, int col, int thres)
{
int res = 0;
for (int i=-1; i<=+1; i++)
for (int j=-1; j<=+1; j++)
if ((i != 0) || (j != 0))
{
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
if (((int)sourceImage[i+row][j+col] - (int)sourceImage[row][col]) >= thres)
{
res++;
}
}
}
return res;
}
int GetCountSmaller(int row, int col, int thres)
{
int res = 0;
for (int i=-1; i<=+1; i++)
for (int j=-1; j<=+1; j++)
if ((i != 0) || (j != 0))
{
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
if (((int)sourceImage[row][col] - (int)sourceImage[i+row][j+col]) >= thres)
{
res++;
}
}
}
return res;
}
int MeanAroundColor(int row, int col, bool useBadPoints)
{
int pointscount = 0;
int res = 0;
for (int i=-1; i<=+1; i++)
for (int j=-1; j<=+1; j++)
if ((i != 0) || (j !=
0))
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
if ((useBadPoints) || (!badPoints[i+row][j+col]))
{
res = res + sourceImage[i+row][j+col];
pointscount++;
if ((i == 0) || (j == 0))
{
res = res + sourceImage[i+row][j+col];
pointscount++;
}
}
}
if (pointscount > 0)
{
res = res / pointscount;
}
return res;
}
int MedianColor(int row, int col, bool useBadPoints)
{
int pointscount = 0;
int points[20];
for (int i=-1; i<=+1; i++)
for (int j=-1; j<=+1; j++)
//if ((i != 0) || (j != 0))
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
if ((useBadPoints) || (!badPoints[i+row][j+col]))
{
pointscount++;
points[
pointscount] = sourceImage[i+row][j+col];
if (i*j == 0)
{
pointscount++;
points[pointscount] = sourceImage[i+row][j+col];
if (i+j == 0)
{
pointscount++;
points[pointscount] = sourceImage[i+row][j+col];
pointscount++;
points[pointscount] = sourceImage[i+row][j+col];
}
}
}
}
if (pointscount > 0)
{
for (int i=pointscount-1; i>=0; i--)
for (int j=1; j<=i; j++)
if (points[j] > points[j+1])
{
int temp = points[j];
points[j] = points[j+1];
points[j+1] = temp;
}
}
if ((pointscount % 2) != 0)
{
pointscount = (pointscount / 2) + 1;
}
else
{
pointscount = pointscount / 2;
}
return points[pointscount];
}
int GetAroundPointsCount(int row, int col)
{
int pointscount = 0;
-
for (int i=-1; i<=+1; i++)
for (int j=-1; j<=+1; j++)
if ((i != 0) || (j != 0))
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
pointscount++;
}
return pointscount;
}
void FilterSinglePoints(int thres)
{
for (int i=0; i<h; i++)
for (int j=0; j<w; j++)
{
int pointsCount = GetAroundPointsCount(i, j);
int countB = GetCountBigger(i, j, thres);
int countS = GetCountSmaller(i, j, thres);
if ((countB == pointsCount) || (countS == pointsCount))
{
diffcount++;
diffs[diffcount].i = i;
diffs[diffcount].j = j;
-
badPoints[i][j] = true;
}
}
}
int GetColorForDiffValue(int row, int col)
{
return MeanAroundColor(row, col, false);
}
int GetColorForResult(
int row, int col)
{
return MedianColor(row, col, false);
}
void FillLines(bool testBlocked)
{
for (int i=0; i<h; i++)
for (int j=0; j<w; j++)
{
// hor ->>>
if (j + 4 < w)
{
if ((resultImage[i][j] == resultImage[i][j+1]) &&
(resultImage[i][j] != resultImage[i][j+2]) &&
(resultImage[i][j] == resultImage[i][j+3]) &&
(resultImage[i][j] == resultImage[i][j+4]))
{
bool blocked = false;
if (testBlocked)
{
if ((i + 1 < h) &&
(resultImage[i+1][j+2] == resultImage[i][j+2]))
{
blocked = true;
}
if ((i - 1 > 0) &&
(resultImage[i-1][j+2] == resultImage[i][j+2]))
{
blocked = true;
}
}
if (!blocked)
{
resultImage[i][j+2] = resultImage[i][j];
}
}
}
// ver |
// \|/
if (i + 4 < h)
{
if ((resultImage[i][j] == resultImage[i+1][j]) &&
(resultImage[i][j] != resultImage[i+2][j]) &&
-
(resultImage[i][j] == resultImage[
i+3][j]) &&
(resultImage[i][j] == resultImage[i+4][j]))
{
bool blocked = false;
if (testBlocked)
{
if ((j + 1 < w) &&
(resultImage[i+2][j+1] == resultImage[i+2][j]))
{
blocked = true;
}
if ((i - 1 > 0) &&
(resultImage[i+2][j-1] == resultImage[i+2][j]))
{
blocked = true;
}
}
if (!blocked)
{
resultImage[i+2][j] = resultImage[i][j];
}
}
}
}
}
bool SameColorAround(int row, int col, int sourcecolor, int thres)
{
bool res = false;
for (int i=-1; i<=+1; i++)
{
for (int j=-1; j<=+1; j++)
if ((i != 0) || (j != 0))
if (((i + row) >= 0) && ((i + row) < h) && ((j + col) >= 0) && ((j + col) < w))
{
if (abs(sourceImage
[row
][col
] - sourceImage
[row+i
][col+j
]) <= thres
) {
res = true;
break;
}
}
if (res) break;
}
-
return res;
}
void Filter(int thres, int sameThres)
{
for (int i=0; i<h; i++)
for (int j=0; j<w; j++)
{
int sourcecolor = sourceImage[i][j];
int aroundcolor = GetColorForDiffValue(i, j);
if ((abs(sourcecolor - aroundcolor
) > thres
) &&
(!SameColorAround(i, j, sourcecolor, sameThres)))
{
diffcount++;
diffs[diffcount].i = i;
diffs[diffcount].j = j;
diffs
[diffcount
].
value =
abs(sourcecolor - aroundcolor
);
badPoints[i][j] = true;
}
}
}
void FilterAvatar(int thres)
{
int moda[256];
for (int i=0; i<h; i++)
{
moda[resultImage[i][0]]++;
moda[resultImage[i][w-1]]++;
}
for (int j=0; j<w; j++)
{
moda[resultImage[0][j]]++;
moda[resultImage[h-1][j]]++;
}
int best=0, bestcount=0;
for (int i=0; i<256; i++)
{
if (moda[i] > bestcount)
{
bestcount = moda[i];
best = i;
}
}
if (bestcount > 350)
{
for (int i=0; i<h; i++)
{
if (abs(resultImage
[i
][0] - best
) >= thres
) {
resultImage[i][0] = best;
}
if (abs(resultImage
[i
][w-
1] - best
) >= thres
) {
resultImage[i][w-1] = best;
}
}
for (int j=0; j<w; j++)
{
if (abs(resultImage
[0][j
] - best
) >= thres
) {
resultImage[0][j] = best;
}
if
(abs(resultImage
[h-
1][j
] - best
) >= thres
) {
resultImage[h-1][j] = best;
}
}
}
}
void Filter2x2Diagonal(int centerThres, int aroundThres, bool centerLighter)
{
int a = 1, b = -1;
if (!centerLighter)
{
a = -a;
b = -b;
}
int matrToUp [4][4] = { {0, 1, 1, 1}, {1, 1, 0, 1}, {1, 0, 1, 1}, {1, 1, 1, 0}};
int matrToDown [4][4] = { {1, 1, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 1}};
for (int i=-1; i<=h-3; i++)
for (int j=-1; j<=w-3; j++)
{
// To up
//
if (abs((int)resultImage
[i+
2][j+
1] -
(int)resultImage
[i+
1][j+
2]) <= centerThres
) {
int center = ((int)resultImage[i+2][j+1] + (int)resultImage[i+1][j+2]) / 2;
bool apply = true;
for (int ii=0; ii<4; ii++)
{
for (int jj=0; jj<4; jj++)
if (((ii + i) >= 0) && ((ii + i) < h) && ((jj + j) >= 0) && ((jj + j) < w))
if ((matrToUp[ii][jj] == 1) &&
((a*center + (int)b*resultImage[i+ii][j+jj]) < aroundThres))
{
apply = false;
break;
}
if (!apply) break;
}
if (apply)
{
badPoints[i+2][j+1] = true;
badPoints[i+1][j+2] = true;
resultImage[i+2][j+1] = MedianColor(i+2, j+1, false);
resultImage[i+1][j+2] = MedianColor(i+
1, j+2, false);
badPoints[i+2][j+1] = false;
badPoints[i+1][j+2] = false;
}
}
// To down
//
if (abs((int)resultImage
[i+
1][j+
1] -
(int)resultImage
[i+
2][j+
2]) <= centerThres
) {
int center = ((int)resultImage[i+1][j+1] + (int)resultImage[i+2][j+2]) / 2;
bool apply = true;
for (int ii=0; ii<4; ii++)
{
for (int jj=0; jj<4; jj++)
if (((ii + i) >= 0) && ((ii + i) < h) && ((jj + j) >= 0) && ((jj + j) < w))
if ((
matrToDown[ii][jj] == 1) &&
((a*center + (int)b*resultImage[i+ii][j+jj]) < aroundThres))
{
apply = false;
break;
}
if (!apply) break;
}
if (apply)
{
badPoints[i+1][j+1] = true;
badPoints[i+2][j+2] = true;
resultImage[i+1][j+1] = MedianColor(i+1, j+1, false);
resultImage[i+2][j+2] = MedianColor(i+2, j+2, false);
badPoints[i+1][j+1] = false;
badPoints[i+2][j+2] = false;
}
}
}
}
void Filter2x2Linear(int centerThres, int aroundThres, bool centerLighter)
{
int a = 1, b = -1;
if (!centerLighter)
{
a = -a;
b = -b;
}
int matrHor [3][4] = { {1, 1, 1, 1}, {1, 0, 0, 1}, {1, 1, 1, 1}};
int matrVer [4][3] = { {1, 1, 1}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1}};
for (int i=-1; i<=h-2; i++)
for (int j=-1; j<=w-3; j++)
{
// Hor
//
if (abs((int)resultImage
[i+
1][j+
1] -
(int)resultImage
[i+
1][j+
2]) <= centerThres
) {
int center = ((int)resultImage[i+1][j+1] + (int)resultImage[i+1][j+2]) / 2;
bool apply = true;
for (int ii=0; ii<3; ii++)
{
for (int jj=0; jj<4; jj++)
if (((ii + i) >= 0) && ((ii + i) < h) && ((jj + j) >= 0) && ((jj + j) < w))
if ((matrHor[ii][jj] == 1) &&
((a*center + (int)b*resultImage[i+ii][j+jj]) < aroundThres))
{
apply = false;
break;
}
if (!apply) break;
}
if (apply)
{
badPoints[i+1][j+1] = true;
badPoints[i+1][j+2] = true;
resultImage[i+1][j+1] = MedianColor(i+1, j+1, false);
resultImage[i+1][j+2] = MedianColor(i+1, j+2, false);
badPoints[i+1][j+1] = false;
badPoints[i+1][j+2] = false;
}
}
}
for (int i=-1; i<=h-3; i++)
for (int j=-1; j<=w-2; j++)
{
// Ver
//
if (abs((int)resultImage
[i+
1][j+
1] -
(int)resultImage
[i+
2][j+
1]) <= centerThres
) {
int center = ((int)resultImage[i+1][j+1] + (int)resultImage[i+2][j+1]) / 2;
bool apply = true;
for (int ii=0; ii<4; ii++)
{
for (int jj=0; jj<3; jj++)
if (((ii + i) >= 0) && ((ii + i) < h) && ((jj + j) >= 0) && ((jj + j) < w))
if ((
matrVer[ii][jj] == 1) &&
((a*center + (int)b*resultImage[i+ii][j+jj]) < aroundThres))
{
apply = false;
break;
}
if (!apply) break;
}
if (apply)
{
badPoints[i+1][j+1] = true;
badPoints[i+2][j+1] = true;
resultImage[i+1][j+1] = MedianColor(i+1, j+1, false);
resultImage[i+2][j+1] = MedianColor(i+2, j+1, false);
badPoints[i+1][j+1] = false;
badPoints[i+2][j+1] = false;
}
}
}
}
void Filter2x2()
{
Filter2x2Diagonal(8, 35, false);
Filter2x2Diagonal(8, 35, true);
Filter2x2Linear(8, 35, false);
Filter2x2Linear(8, 35, true);
}
int main(void)
{
int t;
for (int tt=0; tt<t; tt++)
{
ClearBadPoints();
scanf("%d %d %d", &q, &h, &w
);
ReadImage();
diffcount = 0;
CopySourceToResult();
int thres = 14 - q/2;
-
/*
do
{
ClearBadPoints();
diffcount = 0;
CopyResultToSource();
FilterSinglePoints(thres);
ApplyDiffs();
} while (diffcount > 3);
*/
// Some filter
-
ClearBadPoints();
diffcount = 0;
CopyResultToSource();
int diffthres = 120;
-
int samethres = 0;//12 - q/2;
if (samethres < 0) samethres = 0;
//Filter(diffthres, samethres);
//ApplyDiffs();
-
do
{
ClearBadPoints();
diffcount = 0;
CopyResultToSource();
FilterSinglePoints(thres+1);
ApplyDiffs();
} while (diffcount > 3);
-
// It's ok
-
FillLines(h+w <= 100);
FillLines(h+w <= 100);
FillLines(h+w <= 100);
// It's ok too
-
Filter2x2();
-
if
(q > 3)
do
{
ClearBadPoints();
diffcount = 0;
CopyResultToSource();
FilterSinglePoints(thres);
ApplyDiffs();
} while (diffcount > 3);
/*
if ((h == 100) && (w == 100))
{
FilterAvatar(10);
}
*/
WriteImage();
}
}